mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Fix merge conflicts
This commit is contained in:
commit
3f1718f4c5
340 changed files with 3289 additions and 9498 deletions
|
@ -1,5 +1,4 @@
|
||||||
./.github
|
./.github
|
||||||
./.stryker-tmp
|
|
||||||
./build
|
./build
|
||||||
./coverage
|
./coverage
|
||||||
./node_modules
|
./node_modules
|
||||||
|
|
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
@ -12,6 +12,5 @@ jobs:
|
||||||
uses: shlinkio/github-actions/.github/workflows/web-app-ci.yml@main
|
uses: shlinkio/github-actions/.github/workflows/web-app-ci.yml@main
|
||||||
with:
|
with:
|
||||||
node-version: 18.12
|
node-version: 18.12
|
||||||
with-mutation-tests: true
|
|
||||||
publish-coverage: true
|
publish-coverage: true
|
||||||
force-install: true
|
force-install: true
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
/coverage
|
/coverage
|
||||||
/.stryker-tmp
|
|
||||||
/reports
|
/reports
|
||||||
|
|
||||||
# production
|
# production
|
||||||
|
|
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -4,6 +4,25 @@ 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).
|
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]
|
||||||
|
### Added
|
||||||
|
* *Nothing*
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Update to Vite 4.1
|
||||||
|
* Update to coding standard v2.1.0
|
||||||
|
* [#798](https://github.com/shlinkio/shlink-web-client/issues/798) Remove stryker and mutation testing.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
* *Nothing*
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
* *Nothing*
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* *Nothing*
|
||||||
|
|
||||||
|
|
||||||
## [3.9.1] - 2022-12-31
|
## [3.9.1] - 2022-12-31
|
||||||
### Added
|
### Added
|
||||||
* *Nothing*
|
* *Nothing*
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
[![GitHub release](https://img.shields.io/github/release/shlinkio/shlink-web-client.svg?style=flat-square)](https://github.com/shlinkio/shlink-web-client/releases/latest)
|
[![GitHub release](https://img.shields.io/github/release/shlinkio/shlink-web-client.svg?style=flat-square)](https://github.com/shlinkio/shlink-web-client/releases/latest)
|
||||||
[![Docker pulls](https://img.shields.io/docker/pulls/shlinkio/shlink-web-client.svg?logo=docker&style=flat-square)](https://hub.docker.com/r/shlinkio/shlink-web-client/)
|
[![Docker pulls](https://img.shields.io/docker/pulls/shlinkio/shlink-web-client.svg?logo=docker&style=flat-square)](https://hub.docker.com/r/shlinkio/shlink-web-client/)
|
||||||
[![GitHub license](https://img.shields.io/github/license/shlinkio/shlink-web-client.svg?style=flat-square)](https://github.com/shlinkio/shlink-web-client/blob/main/LICENSE)
|
[![GitHub license](https://img.shields.io/github/license/shlinkio/shlink-web-client.svg?style=flat-square)](https://github.com/shlinkio/shlink-web-client/blob/main/LICENSE)
|
||||||
[![Twitter](https://img.shields.io/twitter/follow/shlinkio?color=blue&label=follow&logo=twitter&style=flat-square)](https://twitter.com/shlinkio)
|
[![Twitter](https://img.shields.io/badge/follow-shlinkio-blue.svg?style=flat-square&logo=twitter&color=blue)](https://twitter.com/shlinkio)
|
||||||
[![Mastodon](https://img.shields.io/mastodon/follow/109329425426175098?color=%236364ff&domain=https%3A%2F%2Ffosstodon.org&label=follow&logo=mastodon&logoColor=white&style=flat-square)](https://fosstodon.org/@shlinkio)
|
[![Mastodon](https://img.shields.io/mastodon/follow/109329425426175098?color=%236364ff&domain=https%3A%2F%2Ffosstodon.org&label=follow&logo=mastodon&logoColor=white&style=flat-square)](https://fosstodon.org/@shlinkio)
|
||||||
[![Paypal Donate](https://img.shields.io/badge/Donate-paypal-blue.svg?style=flat-square&logo=paypal&colorA=cccccc)](https://slnk.to/donate)
|
[![Paypal Donate](https://img.shields.io/badge/Donate-paypal-blue.svg?style=flat-square&logo=paypal&colorA=cccccc)](https://slnk.to/donate)
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ Those servers can be exported and imported in other browsers, but if for some re
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "Main server",
|
"name": "Main server",
|
||||||
"url": "https://doma.in",
|
"url": "https://s.test",
|
||||||
"apiKey": "09c972b7-506b-49f1-a19a-d729e22e599c"
|
"apiKey": "09c972b7-506b-49f1-a19a-d729e22e599c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -85,7 +85,7 @@ If you want to pre-configure a single server, you can provide its config via env
|
||||||
docker run \
|
docker run \
|
||||||
--name shlink-web-client \
|
--name shlink-web-client \
|
||||||
-p 8000:80 \
|
-p 8000:80 \
|
||||||
-e SHLINK_SERVER_URL=https://doma.in \
|
-e SHLINK_SERVER_URL=https://s.test \
|
||||||
-e SHLINK_SERVER_API_KEY=6aeb82c6-e275-4538-a747-31f9abfba63c \
|
-e SHLINK_SERVER_API_KEY=6aeb82c6-e275-4538-a747-31f9abfba63c \
|
||||||
shlinkio/shlink-web-client
|
shlinkio/shlink-web-client
|
||||||
```
|
```
|
||||||
|
|
|
@ -17,7 +17,6 @@ module.exports = {
|
||||||
},
|
},
|
||||||
setupFilesAfterEnv: ['<rootDir>/config/jest/setupTests.ts'],
|
setupFilesAfterEnv: ['<rootDir>/config/jest/setupTests.ts'],
|
||||||
testMatch: ['<rootDir>/test/**/*.test.{ts,tsx}'],
|
testMatch: ['<rootDir>/test/**/*.test.{ts,tsx}'],
|
||||||
modulePathIgnorePatterns: ['<rootDir>/.stryker-tmp'],
|
|
||||||
testEnvironment: 'jsdom',
|
testEnvironment: 'jsdom',
|
||||||
testEnvironmentOptions: {
|
testEnvironmentOptions: {
|
||||||
url: 'http://localhost',
|
url: 'http://localhost',
|
||||||
|
@ -28,7 +27,6 @@ module.exports = {
|
||||||
'^(?!.*\\.(ts|tsx|js|json|scss)$)': '<rootDir>/config/jest/fileTransform.js',
|
'^(?!.*\\.(ts|tsx|js|json|scss)$)': '<rootDir>/config/jest/fileTransform.js',
|
||||||
},
|
},
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
'<rootDir>/.stryker-tmp',
|
|
||||||
'node_modules\/(?!(\@react-leaflet|react-leaflet|leaflet|react-chartjs-2|react-colorful)\/)',
|
'node_modules\/(?!(\@react-leaflet|react-leaflet|leaflet|react-chartjs-2|react-colorful)\/)',
|
||||||
'^.+\\.module\\.scss$',
|
'^.+\\.module\\.scss$',
|
||||||
],
|
],
|
||||||
|
|
10012
package-lock.json
generated
10012
package-lock.json
generated
File diff suppressed because it is too large
Load diff
15
package.json
15
package.json
|
@ -20,8 +20,7 @@
|
||||||
"test:coverage": "npm run test -- --coverage --coverageReporters=text --coverageReporters=text-summary",
|
"test:coverage": "npm run test -- --coverage --coverageReporters=text --coverageReporters=text-summary",
|
||||||
"test:ci": "npm run test:coverage -- --coverageReporters=clover --ci",
|
"test:ci": "npm run test:coverage -- --coverageReporters=clover --ci",
|
||||||
"test:pretty": "npm run test:coverage -- --coverageReporters=html",
|
"test:pretty": "npm run test:coverage -- --coverageReporters=html",
|
||||||
"test:verbose": "npm run test -- --verbose",
|
"test:verbose": "npm run test -- --verbose"
|
||||||
"mutate": "./node_modules/.bin/stryker run --concurrency 4 --ignoreStatic"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/preset-env": "^7.20.2",
|
"@babel/preset-env": "^7.20.2",
|
||||||
|
@ -71,11 +70,8 @@
|
||||||
"workbox-strategies": "^6.5.4"
|
"workbox-strategies": "^6.5.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@shlinkio/eslint-config-js-coding-standard": "~2.0.2",
|
"@shlinkio/eslint-config-js-coding-standard": "~2.1.0",
|
||||||
"@shlinkio/stylelint-config-css-coding-standard": "~1.0.1",
|
"@shlinkio/stylelint-config-css-coding-standard": "~1.0.1",
|
||||||
"@stryker-mutator/core": "^6.3.1",
|
|
||||||
"@stryker-mutator/jest-runner": "^6.3.1",
|
|
||||||
"@stryker-mutator/typescript-checker": "^6.3.1",
|
|
||||||
"@testing-library/jest-dom": "^5.16.5",
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^14.4.3",
|
"@testing-library/user-event": "^14.4.3",
|
||||||
|
@ -91,7 +87,7 @@
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-dom": "^18.0.10",
|
||||||
"@types/react-tag-autocomplete": "^6.3.0",
|
"@types/react-tag-autocomplete": "^6.3.0",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.1.0",
|
||||||
"adm-zip": "^0.5.10",
|
"adm-zip": "^0.5.10",
|
||||||
"babel-jest": "^29.3.1",
|
"babel-jest": "^29.3.1",
|
||||||
"chalk": "^5.2.0",
|
"chalk": "^5.2.0",
|
||||||
|
@ -102,12 +98,11 @@
|
||||||
"jest-environment-jsdom": "^29.3.1",
|
"jest-environment-jsdom": "^29.3.1",
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
"sass": "^1.57.1",
|
"sass": "^1.57.1",
|
||||||
"stryker-cli": "^1.0.2",
|
|
||||||
"stylelint": "^14.16.0",
|
"stylelint": "^14.16.0",
|
||||||
"ts-mockery": "^1.2.0",
|
"ts-mockery": "^1.2.0",
|
||||||
"typescript": "^4.9.4",
|
"typescript": "^4.9.4",
|
||||||
"vite": "^4.0.3",
|
"vite": "^4.1.1",
|
||||||
"vite-plugin-pwa": "^0.14.0"
|
"vite-plugin-pwa": "^0.14.1"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
">0.2%",
|
">0.2%",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import type { ProblemDetailsError } from './types/errors';
|
||||||
import { isInvalidArgumentError } from './utils';
|
import { isInvalidArgumentError } from './utils';
|
||||||
import { ProblemDetailsError } from './types/errors';
|
|
||||||
|
|
||||||
export interface ShlinkApiErrorProps {
|
export interface ShlinkApiErrorProps {
|
||||||
errorData?: ProblemDetailsError;
|
errorData?: ProblemDetailsError;
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import { isEmpty, isNil, reject } from 'ramda';
|
import { isEmpty, isNil, reject } from 'ramda';
|
||||||
import { ShortUrl, ShortUrlData } from '../../short-urls/data';
|
import type { HttpClient } from '../../common/services/HttpClient';
|
||||||
import { OptionalString } from '../../utils/utils';
|
import type { ShortUrl, ShortUrlData } from '../../short-urls/data';
|
||||||
import {
|
import { orderToString } from '../../utils/helpers/ordering';
|
||||||
|
import { stringifyQuery } from '../../utils/helpers/query';
|
||||||
|
import type { OptionalString } from '../../utils/utils';
|
||||||
|
import type {
|
||||||
|
ShlinkDomainRedirects,
|
||||||
|
ShlinkDomainsResponse,
|
||||||
|
ShlinkEditDomainRedirects,
|
||||||
ShlinkHealth,
|
ShlinkHealth,
|
||||||
ShlinkMercureInfo,
|
ShlinkMercureInfo,
|
||||||
|
ShlinkShortUrlData,
|
||||||
|
ShlinkShortUrlsListNormalizedParams,
|
||||||
|
ShlinkShortUrlsListParams,
|
||||||
ShlinkShortUrlsResponse,
|
ShlinkShortUrlsResponse,
|
||||||
ShlinkTags,
|
ShlinkTags,
|
||||||
ShlinkTagsResponse,
|
ShlinkTagsResponse,
|
||||||
ShlinkVisits,
|
ShlinkVisits,
|
||||||
ShlinkVisitsParams,
|
|
||||||
ShlinkShortUrlData,
|
|
||||||
ShlinkDomainsResponse,
|
|
||||||
ShlinkVisitsOverview,
|
ShlinkVisitsOverview,
|
||||||
ShlinkEditDomainRedirects,
|
ShlinkVisitsParams,
|
||||||
ShlinkDomainRedirects,
|
|
||||||
ShlinkShortUrlsListParams,
|
|
||||||
ShlinkShortUrlsListNormalizedParams,
|
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { orderToString } from '../../utils/helpers/ordering';
|
|
||||||
import { isRegularNotFound, parseApiError } from '../utils';
|
import { isRegularNotFound, parseApiError } from '../utils';
|
||||||
import { stringifyQuery } from '../../utils/helpers/query';
|
|
||||||
import { HttpClient } from '../../common/services/HttpClient';
|
|
||||||
|
|
||||||
const buildShlinkBaseUrl = (url: string, version: 2 | 3) => `${url}/rest/v${version}`;
|
const buildShlinkBaseUrl = (url: string, version: 2 | 3) => `${url}/rest/v${version}`;
|
||||||
const rejectNilProps = reject(isNil);
|
const rejectNilProps = reject(isNil);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { hasServerData, ServerWithId } from '../../servers/data';
|
import type { HttpClient } from '../../common/services/HttpClient';
|
||||||
import { GetState } from '../../container/types';
|
import type { GetState } from '../../container/types';
|
||||||
|
import type { ServerWithId } from '../../servers/data';
|
||||||
|
import { hasServerData } from '../../servers/data';
|
||||||
import { ShlinkApiClient } from './ShlinkApiClient';
|
import { ShlinkApiClient } from './ShlinkApiClient';
|
||||||
import { HttpClient } from '../../common/services/HttpClient';
|
|
||||||
|
|
||||||
const apiClients: Record<string, ShlinkApiClient> = {};
|
const apiClients: Record<string, ShlinkApiClient> = {};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import Bottle from 'bottlejs';
|
import type Bottle from 'bottlejs';
|
||||||
import { buildShlinkApiClient } from './ShlinkApiClientBuilder';
|
import { buildShlinkApiClient } from './ShlinkApiClientBuilder';
|
||||||
|
|
||||||
const provideServices = (bottle: Bottle) => {
|
export const provideServices = (bottle: Bottle) => {
|
||||||
bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'HttpClient');
|
bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'HttpClient');
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Visit } from '../../visits/types';
|
import type { ShortUrl, ShortUrlMeta } from '../../short-urls/data';
|
||||||
import { OptionalString } from '../../utils/utils';
|
import type { Order } from '../../utils/helpers/ordering';
|
||||||
import { ShortUrl, ShortUrlMeta } from '../../short-urls/data';
|
import type { OptionalString } from '../../utils/utils';
|
||||||
import { Order } from '../../utils/helpers/ordering';
|
import type { Visit } from '../../visits/types';
|
||||||
|
|
||||||
export interface ShlinkShortUrlsResponse {
|
export interface ShlinkShortUrlsResponse {
|
||||||
data: ShortUrl[];
|
data: ShortUrl[];
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import {
|
import type {
|
||||||
ErrorTypeV2,
|
|
||||||
ErrorTypeV3,
|
|
||||||
InvalidArgumentError,
|
InvalidArgumentError,
|
||||||
InvalidShortUrlDeletion,
|
InvalidShortUrlDeletion,
|
||||||
ProblemDetailsError,
|
ProblemDetailsError,
|
||||||
RegularNotFound,
|
RegularNotFound } from '../types/errors';
|
||||||
|
import {
|
||||||
|
ErrorTypeV2,
|
||||||
|
ErrorTypeV3,
|
||||||
} from '../types/errors';
|
} from '../types/errors';
|
||||||
|
|
||||||
const isProblemDetails = (e: unknown): e is ProblemDetailsError =>
|
const isProblemDetails = (e: unknown): e is ProblemDetailsError =>
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { useEffect, FC } from 'react';
|
|
||||||
import { Route, Routes, useLocation } from 'react-router-dom';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { NotFound } from '../common/NotFound';
|
import type { FC } from 'react';
|
||||||
import { ServersMap } from '../servers/data';
|
import { useEffect } from 'react';
|
||||||
import { Settings } from '../settings/reducers/settings';
|
import { Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import { changeThemeInMarkup } from '../utils/theme';
|
|
||||||
import { AppUpdateBanner } from '../common/AppUpdateBanner';
|
import { AppUpdateBanner } from '../common/AppUpdateBanner';
|
||||||
|
import { NotFound } from '../common/NotFound';
|
||||||
|
import type { ServersMap } from '../servers/data';
|
||||||
|
import type { Settings } from '../settings/reducers/settings';
|
||||||
import { forceUpdate } from '../utils/helpers/sw';
|
import { forceUpdate } from '../utils/helpers/sw';
|
||||||
|
import { changeThemeInMarkup } from '../utils/theme';
|
||||||
import './App.scss';
|
import './App.scss';
|
||||||
|
|
||||||
interface AppProps {
|
interface AppProps {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import Bottle from 'bottlejs';
|
import type Bottle from 'bottlejs';
|
||||||
import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';
|
import type { ConnectDecorator } from '../../container/types';
|
||||||
import { App } from '../App';
|
import { App } from '../App';
|
||||||
import { ConnectDecorator } from '../../container/types';
|
import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';
|
||||||
|
|
||||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
// Components
|
// Components
|
||||||
bottle.serviceFactory(
|
bottle.serviceFactory(
|
||||||
'App',
|
'App',
|
||||||
|
@ -23,5 +23,3 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);
|
bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);
|
||||||
bottle.serviceFactory('resetAppUpdate', () => resetAppUpdate);
|
bottle.serviceFactory('resetAppUpdate', () => resetAppUpdate);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { FC, MouseEventHandler } from 'react';
|
|
||||||
import { Alert, Button } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faSyncAlt as reloadIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faSyncAlt as reloadIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { FC, MouseEventHandler } from 'react';
|
||||||
|
import { Alert, Button } from 'reactstrap';
|
||||||
import { useToggle } from '../utils/helpers/hooks';
|
import { useToggle } from '../utils/helpers/hooks';
|
||||||
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
import './AppUpdateBanner.scss';
|
import './AppUpdateBanner.scss';
|
||||||
|
|
||||||
interface AppUpdateBannerProps {
|
interface AppUpdateBannerProps {
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
import {
|
import {
|
||||||
faList as listIcon,
|
|
||||||
faLink as createIcon,
|
|
||||||
faTags as tagsIcon,
|
|
||||||
faPen as editIcon,
|
|
||||||
faHome as overviewIcon,
|
|
||||||
faGlobe as domainsIcon,
|
faGlobe as domainsIcon,
|
||||||
|
faHome as overviewIcon,
|
||||||
|
faLink as createIcon,
|
||||||
|
faList as listIcon,
|
||||||
|
faPen as editIcon,
|
||||||
|
faTags as tagsIcon,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { FC } from 'react';
|
|
||||||
import { NavLink, NavLinkProps, useLocation } from 'react-router-dom';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { DeleteServerButtonProps } from '../servers/DeleteServerButton';
|
import type { FC } from 'react';
|
||||||
import { isServerWithId, SelectedServer } from '../servers/data';
|
import type { NavLinkProps } from 'react-router-dom';
|
||||||
|
import { NavLink, useLocation } from 'react-router-dom';
|
||||||
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
import { isServerWithId } from '../servers/data';
|
||||||
|
import type { DeleteServerButtonProps } from '../servers/DeleteServerButton';
|
||||||
import './AsideMenu.scss';
|
import './AsideMenu.scss';
|
||||||
|
|
||||||
export interface AsideMenuProps {
|
export interface AsideMenuProps {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Component, ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
import { Component } from 'react';
|
||||||
import { Button } from 'reactstrap';
|
import { Button } from 'reactstrap';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { useEffect } from 'react';
|
import { faExternalLinkAlt, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { isEmpty, values } from 'ramda';
|
import { isEmpty, values } from 'ramda';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { ExternalLink } from 'react-external-link';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { Card, Row } from 'reactstrap';
|
import { Card, Row } from 'reactstrap';
|
||||||
import { ExternalLink } from 'react-external-link';
|
import type { ServersMap } from '../servers/data';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faExternalLinkAlt, faPlus } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { ServersListGroup } from '../servers/ServersListGroup';
|
import { ServersListGroup } from '../servers/ServersListGroup';
|
||||||
import { ServersMap } from '../servers/data';
|
|
||||||
import { ShlinkLogo } from './img/ShlinkLogo';
|
import { ShlinkLogo } from './img/ShlinkLogo';
|
||||||
import './Home.scss';
|
import './Home.scss';
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { faChevronDown as arrowIcon, faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faChevronDown as arrowIcon, faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { FC, useEffect } from 'react';
|
import classNames from 'classnames';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
|
import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
|
||||||
import classNames from 'classnames';
|
|
||||||
import { useToggle } from '../utils/helpers/hooks';
|
import { useToggle } from '../utils/helpers/hooks';
|
||||||
import { ShlinkLogo } from './img/ShlinkLogo';
|
import { ShlinkLogo } from './img/ShlinkLogo';
|
||||||
import './MainHeader.scss';
|
import './MainHeader.scss';
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import { FC, useEffect } from 'react';
|
|
||||||
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
|
||||||
import { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { withSelectedServer } from '../servers/helpers/withSelectedServer';
|
import type { FC } from 'react';
|
||||||
import { useSwipeable, useToggle } from '../utils/helpers/hooks';
|
import { useEffect } from 'react';
|
||||||
import { supportsDomainVisits, supportsNonOrphanVisits } from '../utils/helpers/features';
|
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import { isReachableServer } from '../servers/data';
|
import { isReachableServer } from '../servers/data';
|
||||||
|
import { withSelectedServer } from '../servers/helpers/withSelectedServer';
|
||||||
|
import { supportsDomainVisits, supportsNonOrphanVisits } from '../utils/helpers/features';
|
||||||
|
import { useSwipeable, useToggle } from '../utils/helpers/hooks';
|
||||||
|
import type { AsideMenuProps } from './AsideMenu';
|
||||||
import { NotFound } from './NotFound';
|
import { NotFound } from './NotFound';
|
||||||
import { AsideMenuProps } from './AsideMenu';
|
|
||||||
import './MenuLayout.scss';
|
import './MenuLayout.scss';
|
||||||
|
|
||||||
interface MenuLayoutProps {
|
interface MenuLayoutProps {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { FC, PropsWithChildren } from 'react';
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
import './NoMenuLayout.scss';
|
import './NoMenuLayout.scss';
|
||||||
|
|
||||||
export const NoMenuLayout: FC<PropsWithChildren<unknown>> = ({ children }) => (
|
export const NoMenuLayout: FC<PropsWithChildren<unknown>> = ({ children }) => (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { FC, PropsWithChildren } from 'react';
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { FC, PropsWithChildren, useEffect } from 'react';
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
export const ScrollToTop: FC<PropsWithChildren<unknown>> = ({ children }) => {
|
export const ScrollToTop: FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { pipe } from 'ramda';
|
import { pipe } from 'ramda';
|
||||||
import { ExternalLink } from 'react-external-link';
|
import { ExternalLink } from 'react-external-link';
|
||||||
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
import { isReachableServer } from '../servers/data';
|
||||||
import { versionToPrintable, versionToSemVer } from '../utils/helpers/version';
|
import { versionToPrintable, versionToSemVer } from '../utils/helpers/version';
|
||||||
import { isReachableServer, SelectedServer } from '../servers/data';
|
|
||||||
|
|
||||||
const SHLINK_WEB_CLIENT_VERSION = '%_VERSION_%';
|
const SHLINK_WEB_CLIENT_VERSION = '%_VERSION_%';
|
||||||
const normalizeVersion = pipe(versionToSemVer(), versionToPrintable);
|
const normalizeVersion = pipe(versionToSemVer(), versionToPrintable);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { SelectedServer } from '../servers/data';
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
import type { Sidebar } from './reducers/sidebar';
|
||||||
import { ShlinkVersions } from './ShlinkVersions';
|
import { ShlinkVersions } from './ShlinkVersions';
|
||||||
import { Sidebar } from './reducers/sidebar';
|
|
||||||
import './ShlinkVersionsContainer.scss';
|
import './ShlinkVersionsContainer.scss';
|
||||||
|
|
||||||
export interface ShlinkVersionsContainerProps {
|
export interface ShlinkVersionsContainerProps {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { FC } from 'react';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import type { FC } from 'react';
|
||||||
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
|
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
|
||||||
|
import type {
|
||||||
|
NumberOrEllipsis } from '../utils/helpers/pagination';
|
||||||
import {
|
import {
|
||||||
pageIsEllipsis,
|
|
||||||
keyForPage,
|
keyForPage,
|
||||||
NumberOrEllipsis,
|
pageIsEllipsis,
|
||||||
progressivePagination,
|
|
||||||
prettifyPageNumber,
|
prettifyPageNumber,
|
||||||
|
progressivePagination,
|
||||||
} from '../utils/helpers/pagination';
|
} from '../utils/helpers/pagination';
|
||||||
import './SimplePaginator.scss';
|
import './SimplePaginator.scss';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Fetch } from '../../utils/types';
|
import type { Fetch } from '../../utils/types';
|
||||||
|
|
||||||
const applicationJsonHeader = { 'Content-Type': 'application/json' };
|
const applicationJsonHeader = { 'Content-Type': 'application/json' };
|
||||||
const withJsonContentType = (options?: RequestInit): RequestInit | undefined => {
|
const withJsonContentType = (options?: RequestInit): RequestInit | undefined => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { saveUrl } from '../../utils/helpers/files';
|
import { saveUrl } from '../../utils/helpers/files';
|
||||||
import { HttpClient } from './HttpClient';
|
import type { HttpClient } from './HttpClient';
|
||||||
|
|
||||||
export class ImageDownloader {
|
export class ImageDownloader {
|
||||||
public constructor(private readonly httpClient: HttpClient, private readonly window: Window) {}
|
public constructor(private readonly httpClient: HttpClient, private readonly window: Window) {}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { NormalizedVisit } from '../../visits/types';
|
import type { ExportableShortUrl } from '../../short-urls/data';
|
||||||
import { ExportableShortUrl } from '../../short-urls/data';
|
import type { JsonToCsv } from '../../utils/helpers/csvjson';
|
||||||
import { saveCsv } from '../../utils/helpers/files';
|
import { saveCsv } from '../../utils/helpers/files';
|
||||||
import { JsonToCsv } from '../../utils/helpers/csvjson';
|
import type { NormalizedVisit } from '../../visits/types';
|
||||||
|
|
||||||
export class ReportExporter {
|
export class ReportExporter {
|
||||||
public constructor(private readonly window: Window, private readonly jsonToCsv: JsonToCsv) {}
|
public constructor(private readonly window: Window, private readonly jsonToCsv: JsonToCsv) {}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
import Bottle from 'bottlejs';
|
import type Bottle from 'bottlejs';
|
||||||
import { ScrollToTop } from '../ScrollToTop';
|
import type { ConnectDecorator } from '../../container/types';
|
||||||
import { MainHeader } from '../MainHeader';
|
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
|
||||||
import { Home } from '../Home';
|
|
||||||
import { MenuLayout } from '../MenuLayout';
|
|
||||||
import { AsideMenu } from '../AsideMenu';
|
import { AsideMenu } from '../AsideMenu';
|
||||||
import { ErrorHandler } from '../ErrorHandler';
|
import { ErrorHandler } from '../ErrorHandler';
|
||||||
import { ShlinkVersionsContainer } from '../ShlinkVersionsContainer';
|
import { Home } from '../Home';
|
||||||
import { ConnectDecorator } from '../../container/types';
|
import { MainHeader } from '../MainHeader';
|
||||||
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
|
import { MenuLayout } from '../MenuLayout';
|
||||||
import { sidebarNotPresent, sidebarPresent } from '../reducers/sidebar';
|
import { sidebarNotPresent, sidebarPresent } from '../reducers/sidebar';
|
||||||
|
import { ScrollToTop } from '../ScrollToTop';
|
||||||
|
import { ShlinkVersionsContainer } from '../ShlinkVersionsContainer';
|
||||||
|
import { HttpClient } from './HttpClient';
|
||||||
import { ImageDownloader } from './ImageDownloader';
|
import { ImageDownloader } from './ImageDownloader';
|
||||||
import { ReportExporter } from './ReportExporter';
|
import { ReportExporter } from './ReportExporter';
|
||||||
import { HttpClient } from './HttpClient';
|
|
||||||
|
|
||||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
// Services
|
// Services
|
||||||
bottle.constant('window', window);
|
bottle.constant('window', window);
|
||||||
bottle.constant('console', console);
|
bottle.constant('console', console);
|
||||||
|
@ -62,5 +62,3 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('sidebarPresent', () => sidebarPresent);
|
bottle.serviceFactory('sidebarPresent', () => sidebarPresent);
|
||||||
bottle.serviceFactory('sidebarNotPresent', () => sidebarNotPresent);
|
bottle.serviceFactory('sidebarNotPresent', () => sidebarNotPresent);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import Bottle, { IContainer } from 'bottlejs';
|
import type { IContainer } from 'bottlejs';
|
||||||
import { connect as reduxConnect } from 'react-redux';
|
import Bottle from 'bottlejs';
|
||||||
import { pick } from 'ramda';
|
import { pick } from 'ramda';
|
||||||
import provideApiServices from '../api/services/provideServices';
|
import { connect as reduxConnect } from 'react-redux';
|
||||||
import provideCommonServices from '../common/services/provideServices';
|
import { provideServices as provideApiServices } from '../api/services/provideServices';
|
||||||
import provideShortUrlsServices from '../short-urls/services/provideServices';
|
import { provideServices as provideAppServices } from '../app/services/provideServices';
|
||||||
import provideServersServices from '../servers/services/provideServices';
|
import { provideServices as provideCommonServices } from '../common/services/provideServices';
|
||||||
import provideVisitsServices from '../visits/services/provideServices';
|
import { provideServices as provideDomainsServices } from '../domains/services/provideServices';
|
||||||
import provideTagsServices from '../tags/services/provideServices';
|
import { provideServices as provideMercureServices } from '../mercure/services/provideServices';
|
||||||
import provideUtilsServices from '../utils/services/provideServices';
|
import { provideServices as provideServersServices } from '../servers/services/provideServices';
|
||||||
import provideMercureServices from '../mercure/services/provideServices';
|
import { provideServices as provideSettingsServices } from '../settings/services/provideServices';
|
||||||
import provideSettingsServices from '../settings/services/provideServices';
|
import { provideServices as provideShortUrlsServices } from '../short-urls/services/provideServices';
|
||||||
import provideDomainsServices from '../domains/services/provideServices';
|
import { provideServices as provideTagsServices } from '../tags/services/provideServices';
|
||||||
import provideAppServices from '../app/services/provideServices';
|
import { provideServices as provideUtilsServices } from '../utils/services/provideServices';
|
||||||
import { ConnectDecorator } from './types';
|
import { provideServices as provideVisitsServices } from '../visits/services/provideServices';
|
||||||
|
import type { ConnectDecorator } from './types';
|
||||||
|
|
||||||
type LazyActionMap = Record<string, Function>;
|
type LazyActionMap = Record<string, Function>;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { IContainer } from 'bottlejs';
|
|
||||||
import { save, load, RLSOptions } from 'redux-localstorage-simple';
|
|
||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
import reducer from '../reducers';
|
import type { IContainer } from 'bottlejs';
|
||||||
|
import type { RLSOptions } from 'redux-localstorage-simple';
|
||||||
|
import { load, save } from 'redux-localstorage-simple';
|
||||||
|
import { initReducers } from '../reducers';
|
||||||
import { migrateDeprecatedSettings } from '../settings/helpers';
|
import { migrateDeprecatedSettings } from '../settings/helpers';
|
||||||
import { ShlinkState } from './types';
|
import type { ShlinkState } from './types';
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
const localStorageConfig: RLSOptions = {
|
const localStorageConfig: RLSOptions = {
|
||||||
|
@ -16,7 +17,7 @@ const preloadedState = migrateDeprecatedSettings(load(localStorageConfig) as Shl
|
||||||
|
|
||||||
export const setUpStore = (container: IContainer) => configureStore({
|
export const setUpStore = (container: IContainer) => configureStore({
|
||||||
devTools: !isProduction,
|
devTools: !isProduction,
|
||||||
reducer: reducer(container),
|
reducer: initReducers(container),
|
||||||
preloadedState,
|
preloadedState,
|
||||||
middleware: (defaultMiddlewaresIncludingReduxThunk) =>
|
middleware: (defaultMiddlewaresIncludingReduxThunk) =>
|
||||||
defaultMiddlewaresIncludingReduxThunk({ immutableCheck: false, serializableCheck: false }) // State is too big for these
|
defaultMiddlewaresIncludingReduxThunk({ immutableCheck: false, serializableCheck: false }) // State is too big for these
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
import { MercureInfo } from '../mercure/reducers/mercureInfo';
|
import type { Sidebar } from '../common/reducers/sidebar';
|
||||||
import { SelectedServer, ServersMap } from '../servers/data';
|
import type { DomainsList } from '../domains/reducers/domainsList';
|
||||||
import { Settings } from '../settings/reducers/settings';
|
import type { MercureInfo } from '../mercure/reducers/mercureInfo';
|
||||||
import { ShortUrlCreation } from '../short-urls/reducers/shortUrlCreation';
|
import type { SelectedServer, ServersMap } from '../servers/data';
|
||||||
import { ShortUrlDeletion } from '../short-urls/reducers/shortUrlDeletion';
|
import type { Settings } from '../settings/reducers/settings';
|
||||||
import { ShortUrlEdition } from '../short-urls/reducers/shortUrlEdition';
|
import type { ShortUrlCreation } from '../short-urls/reducers/shortUrlCreation';
|
||||||
import { ShortUrlsList } from '../short-urls/reducers/shortUrlsList';
|
import type { ShortUrlDeletion } from '../short-urls/reducers/shortUrlDeletion';
|
||||||
import { TagDeletion } from '../tags/reducers/tagDelete';
|
import type { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail';
|
||||||
import { TagEdition } from '../tags/reducers/tagEdit';
|
import type { ShortUrlEdition } from '../short-urls/reducers/shortUrlEdition';
|
||||||
import { TagsList } from '../tags/reducers/tagsList';
|
import type { ShortUrlsList } from '../short-urls/reducers/shortUrlsList';
|
||||||
import { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail';
|
import type { TagDeletion } from '../tags/reducers/tagDelete';
|
||||||
import { ShortUrlVisits } from '../visits/reducers/shortUrlVisits';
|
import type { TagEdition } from '../tags/reducers/tagEdit';
|
||||||
import { TagVisits } from '../visits/reducers/tagVisits';
|
import type { TagsList } from '../tags/reducers/tagsList';
|
||||||
import { DomainsList } from '../domains/reducers/domainsList';
|
import type { DomainVisits } from '../visits/reducers/domainVisits';
|
||||||
import { VisitsOverview } from '../visits/reducers/visitsOverview';
|
import type { ShortUrlVisits } from '../visits/reducers/shortUrlVisits';
|
||||||
import { Sidebar } from '../common/reducers/sidebar';
|
import type { TagVisits } from '../visits/reducers/tagVisits';
|
||||||
import { DomainVisits } from '../visits/reducers/domainVisits';
|
import type { VisitsInfo } from '../visits/reducers/types';
|
||||||
import { VisitsInfo } from '../visits/reducers/types';
|
import type { VisitsOverview } from '../visits/reducers/visitsOverview';
|
||||||
|
|
||||||
export interface ShlinkState {
|
export interface ShlinkState {
|
||||||
servers: ServersMap;
|
servers: ServersMap;
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import { FC, useEffect } from 'react';
|
|
||||||
import { UncontrolledTooltip } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faDotCircle as defaultDomainIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faDotCircle as defaultDomainIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { ShlinkDomainRedirects } from '../api/types';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { OptionalString } from '../utils/utils';
|
import type { FC } from 'react';
|
||||||
import { SelectedServer } from '../servers/data';
|
import { useEffect } from 'react';
|
||||||
import { Domain } from './data';
|
import { UncontrolledTooltip } from 'reactstrap';
|
||||||
import { DomainStatusIcon } from './helpers/DomainStatusIcon';
|
import type { ShlinkDomainRedirects } from '../api/types';
|
||||||
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
import type { OptionalString } from '../utils/utils';
|
||||||
|
import type { Domain } from './data';
|
||||||
import { DomainDropdown } from './helpers/DomainDropdown';
|
import { DomainDropdown } from './helpers/DomainDropdown';
|
||||||
import { EditDomainRedirects } from './reducers/domainRedirects';
|
import { DomainStatusIcon } from './helpers/DomainStatusIcon';
|
||||||
|
import type { EditDomainRedirects } from './reducers/domainRedirects';
|
||||||
|
|
||||||
interface DomainRowProps {
|
interface DomainRowProps {
|
||||||
domain: Domain;
|
domain: Domain;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { Button, DropdownItem, Input, InputGroup, UncontrolledTooltip, InputProps } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faUndo } from '@fortawesome/free-solid-svg-icons';
|
import { faUndo } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { isEmpty, pipe } from 'ramda';
|
import { isEmpty, pipe } from 'ramda';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import type { InputProps } from 'reactstrap';
|
||||||
|
import { Button, DropdownItem, Input, InputGroup, UncontrolledTooltip } from 'reactstrap';
|
||||||
import { DropdownBtn } from '../utils/DropdownBtn';
|
import { DropdownBtn } from '../utils/DropdownBtn';
|
||||||
import { useToggle } from '../utils/helpers/hooks';
|
import { useToggle } from '../utils/helpers/hooks';
|
||||||
import { DomainsList } from './reducers/domainsList';
|
import type { DomainsList } from './reducers/domainsList';
|
||||||
import './DomainSelector.scss';
|
import './DomainSelector.scss';
|
||||||
|
|
||||||
export interface DomainSelectorProps extends Omit<InputProps, 'onChange'> {
|
export interface DomainSelectorProps extends Omit<InputProps, 'onChange'> {
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { FC, useEffect } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { ShlinkApiError } from '../api/ShlinkApiError';
|
||||||
|
import type { SelectedServer } from '../servers/data';
|
||||||
import { Message } from '../utils/Message';
|
import { Message } from '../utils/Message';
|
||||||
import { Result } from '../utils/Result';
|
import { Result } from '../utils/Result';
|
||||||
import { ShlinkApiError } from '../api/ShlinkApiError';
|
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
|
||||||
import { SearchField } from '../utils/SearchField';
|
import { SearchField } from '../utils/SearchField';
|
||||||
import { EditDomainRedirects } from './reducers/domainRedirects';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
import { SelectedServer } from '../servers/data';
|
|
||||||
import { DomainsList } from './reducers/domainsList';
|
|
||||||
import { DomainRow } from './DomainRow';
|
import { DomainRow } from './DomainRow';
|
||||||
|
import type { EditDomainRedirects } from './reducers/domainRedirects';
|
||||||
|
import type { DomainsList } from './reducers/domainsList';
|
||||||
|
|
||||||
interface ManageDomainsProps {
|
interface ManageDomainsProps {
|
||||||
listDomains: Function;
|
listDomains: Function;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ShlinkDomain } from '../../api/types';
|
import type { ShlinkDomain } from '../../api/types';
|
||||||
|
|
||||||
export type DomainStatus = 'validating' | 'valid' | 'invalid';
|
export type DomainStatus = 'validating' | 'valid' | 'invalid';
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import { FC } from 'react';
|
|
||||||
import { DropdownItem } from 'reactstrap';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { faChartPie as pieChartIcon, faEdit as editIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faChartPie as pieChartIcon, faEdit as editIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { useToggle } from '../../utils/helpers/hooks';
|
import type { FC } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { DropdownItem } from 'reactstrap';
|
||||||
|
import type { SelectedServer } from '../../servers/data';
|
||||||
|
import { getServerId } from '../../servers/data';
|
||||||
import { DropdownBtnMenu } from '../../utils/DropdownBtnMenu';
|
import { DropdownBtnMenu } from '../../utils/DropdownBtnMenu';
|
||||||
import { EditDomainRedirectsModal } from './EditDomainRedirectsModal';
|
|
||||||
import { Domain } from '../data';
|
|
||||||
import { EditDomainRedirects } from '../reducers/domainRedirects';
|
|
||||||
import { supportsDefaultDomainRedirectsEdition, supportsDomainVisits } from '../../utils/helpers/features';
|
import { supportsDefaultDomainRedirectsEdition, supportsDomainVisits } from '../../utils/helpers/features';
|
||||||
import { getServerId, SelectedServer } from '../../servers/data';
|
import { useToggle } from '../../utils/helpers/hooks';
|
||||||
import { DEFAULT_DOMAIN } from '../../visits/reducers/domainVisits';
|
import { DEFAULT_DOMAIN } from '../../visits/reducers/domainVisits';
|
||||||
|
import type { Domain } from '../data';
|
||||||
|
import type { EditDomainRedirects } from '../reducers/domainRedirects';
|
||||||
|
import { EditDomainRedirectsModal } from './EditDomainRedirectsModal';
|
||||||
|
|
||||||
interface DomainDropdownProps {
|
interface DomainDropdownProps {
|
||||||
domain: Domain;
|
domain: Domain;
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { FC, useEffect, useRef, useState } from 'react';
|
|
||||||
import { UncontrolledTooltip } from 'reactstrap';
|
|
||||||
import { ExternalLink } from 'react-external-link';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import {
|
import {
|
||||||
faTimes as invalidIcon,
|
|
||||||
faCheck as checkIcon,
|
faCheck as checkIcon,
|
||||||
faCircleNotch as loadingStatusIcon,
|
faCircleNotch as loadingStatusIcon,
|
||||||
|
faTimes as invalidIcon,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { MediaMatcher } from '../../utils/types';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { mutableRefToElementRef } from '../../utils/helpers/components';
|
import type { FC } from 'react';
|
||||||
import { DomainStatus } from '../data';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { ExternalLink } from 'react-external-link';
|
||||||
|
import { UncontrolledTooltip } from 'reactstrap';
|
||||||
|
import { useElementRef } from '../../utils/helpers/hooks';
|
||||||
|
import type { MediaMatcher } from '../../utils/types';
|
||||||
|
import type { DomainStatus } from '../data';
|
||||||
|
|
||||||
interface DomainStatusIconProps {
|
interface DomainStatusIconProps {
|
||||||
status: DomainStatus;
|
status: DomainStatus;
|
||||||
|
@ -17,7 +18,7 @@ interface DomainStatusIconProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DomainStatusIcon: FC<DomainStatusIconProps> = ({ status, matchMedia = window.matchMedia }) => {
|
export const DomainStatusIcon: FC<DomainStatusIconProps> = ({ status, matchMedia = window.matchMedia }) => {
|
||||||
const ref = useRef<HTMLSpanElement>();
|
const ref = useElementRef<HTMLSpanElement>();
|
||||||
const matchesMobile = () => matchMedia('(max-width: 991px)').matches;
|
const matchesMobile = () => matchMedia('(max-width: 991px)').matches;
|
||||||
const [isMobile, setIsMobile] = useState<boolean>(matchesMobile());
|
const [isMobile, setIsMobile] = useState<boolean>(matchesMobile());
|
||||||
|
|
||||||
|
@ -35,13 +36,13 @@ export const DomainStatusIcon: FC<DomainStatusIconProps> = ({ status, matchMedia
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span ref={mutableRefToElementRef(ref)}>
|
<span ref={ref}>
|
||||||
{status === 'valid'
|
{status === 'valid'
|
||||||
? <FontAwesomeIcon fixedWidth icon={checkIcon} className="text-muted" />
|
? <FontAwesomeIcon fixedWidth icon={checkIcon} className="text-muted" />
|
||||||
: <FontAwesomeIcon fixedWidth icon={invalidIcon} className="text-danger" />}
|
: <FontAwesomeIcon fixedWidth icon={invalidIcon} className="text-danger" />}
|
||||||
</span>
|
</span>
|
||||||
<UncontrolledTooltip
|
<UncontrolledTooltip
|
||||||
target={(() => ref.current) as any}
|
target={ref}
|
||||||
placement={isMobile ? 'top-start' : 'left'}
|
placement={isMobile ? 'top-start' : 'left'}
|
||||||
autohide={status === 'valid'}
|
autohide={status === 'valid'}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { FC, useState } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import { useState } from 'react';
|
||||||
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
||||||
import { ShlinkDomain } from '../../api/types';
|
import type { ShlinkDomain } from '../../api/types';
|
||||||
import { InputFormGroup, InputFormGroupProps } from '../../utils/forms/InputFormGroup';
|
import type { InputFormGroupProps } from '../../utils/forms/InputFormGroup';
|
||||||
import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/utils';
|
import { InputFormGroup } from '../../utils/forms/InputFormGroup';
|
||||||
import { InfoTooltip } from '../../utils/InfoTooltip';
|
import { InfoTooltip } from '../../utils/InfoTooltip';
|
||||||
import { EditDomainRedirects } from '../reducers/domainRedirects';
|
import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/utils';
|
||||||
|
import type { EditDomainRedirects } from '../reducers/domainRedirects';
|
||||||
|
|
||||||
interface EditDomainRedirectsModalProps {
|
interface EditDomainRedirectsModalProps {
|
||||||
domain: ShlinkDomain;
|
domain: ShlinkDomain;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import type { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
|
import type { ShlinkDomainRedirects } from '../../api/types';
|
||||||
import { createAsyncThunk } from '../../utils/helpers/redux';
|
import { createAsyncThunk } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
|
||||||
import { ShlinkDomainRedirects } from '../../api/types';
|
|
||||||
|
|
||||||
const EDIT_DOMAIN_REDIRECTS = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS';
|
const EDIT_DOMAIN_REDIRECTS = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS';
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { createSlice, createAction, SliceCaseReducers, AsyncThunk } from '@reduxjs/toolkit';
|
import type { AsyncThunk, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||||
import { createAsyncThunk } from '../../utils/helpers/redux';
|
import { createAction, createSlice } from '@reduxjs/toolkit';
|
||||||
import { ShlinkDomainRedirects } from '../../api/types';
|
import type { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import type { ShlinkDomainRedirects } from '../../api/types';
|
||||||
import { Domain, DomainStatus } from '../data';
|
import type { ProblemDetailsError } from '../../api/types/errors';
|
||||||
import { hasServerData } from '../../servers/data';
|
|
||||||
import { replaceAuthorityFromUri } from '../../utils/helpers/uri';
|
|
||||||
import { ProblemDetailsError } from '../../api/types/errors';
|
|
||||||
import { parseApiError } from '../../api/utils';
|
import { parseApiError } from '../../api/utils';
|
||||||
import { EditDomainRedirects } from './domainRedirects';
|
import { hasServerData } from '../../servers/data';
|
||||||
|
import { createAsyncThunk } from '../../utils/helpers/redux';
|
||||||
|
import { replaceAuthorityFromUri } from '../../utils/helpers/uri';
|
||||||
|
import type { Domain, DomainStatus } from '../data';
|
||||||
|
import type { EditDomainRedirects } from './domainRedirects';
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/domainsList';
|
const REDUCER_PREFIX = 'shlink/domainsList';
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
import type Bottle from 'bottlejs';
|
||||||
import { prop } from 'ramda';
|
import { prop } from 'ramda';
|
||||||
import Bottle from 'bottlejs';
|
import type { ConnectDecorator } from '../../container/types';
|
||||||
import { ConnectDecorator } from '../../container/types';
|
|
||||||
import { domainsListReducerCreator } from '../reducers/domainsList';
|
|
||||||
import { DomainSelector } from '../DomainSelector';
|
import { DomainSelector } from '../DomainSelector';
|
||||||
import { ManageDomains } from '../ManageDomains';
|
import { ManageDomains } from '../ManageDomains';
|
||||||
import { editDomainRedirects } from '../reducers/domainRedirects';
|
import { editDomainRedirects } from '../reducers/domainRedirects';
|
||||||
|
import { domainsListReducerCreator } from '../reducers/domainsList';
|
||||||
|
|
||||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
// Components
|
// Components
|
||||||
bottle.serviceFactory('DomainSelector', () => DomainSelector);
|
bottle.serviceFactory('DomainSelector', () => DomainSelector);
|
||||||
bottle.decorator('DomainSelector', connect(['domainsList'], ['listDomains']));
|
bottle.decorator('DomainSelector', connect(['domainsList'], ['listDomains']));
|
||||||
|
@ -32,5 +32,3 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('editDomainRedirects', editDomainRedirects, 'buildShlinkApiClient');
|
bottle.serviceFactory('editDomainRedirects', editDomainRedirects, 'buildShlinkApiClient');
|
||||||
bottle.serviceFactory('checkDomainHealth', prop('checkDomainHealth'), 'domainsListReducerCreator');
|
bottle.serviceFactory('checkDomainHealth', prop('checkDomainHealth'), 'domainsListReducerCreator');
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
import 'chart.js/auto'; // TODO Import specific ones to reduce bundle size https://react-chartjs-2.js.org/docs/migration-to-v4/#tree-shaking
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import pack from '../package.json';
|
import pack from '../package.json';
|
||||||
import { container } from './container';
|
import { container } from './container';
|
||||||
import { setUpStore } from './container/store';
|
import { setUpStore } from './container/store';
|
||||||
import { fixLeafletIcons } from './utils/helpers/leaflet';
|
|
||||||
import { register as registerServiceWorker } from './serviceWorkerRegistration';
|
import { register as registerServiceWorker } from './serviceWorkerRegistration';
|
||||||
import 'chart.js/auto'; // TODO Import specific ones to reduce bundle size https://react-chartjs-2.js.org/docs/migration-to-v4/#tree-shaking
|
import { fixLeafletIcons } from './utils/helpers/leaflet';
|
||||||
import 'react-datepicker/dist/react-datepicker.css';
|
|
||||||
import 'leaflet/dist/leaflet.css';
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
import 'leaflet/dist/leaflet.css';
|
||||||
|
import 'react-datepicker/dist/react-datepicker.css';
|
||||||
|
|
||||||
// This overwrites icons used for leaflet maps, fixing some issues caused by webpack while processing the CSS
|
// This overwrites icons used for leaflet maps, fixing some issues caused by webpack while processing the CSS
|
||||||
fixLeafletIcons();
|
fixLeafletIcons();
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { FC, useEffect } from 'react';
|
|
||||||
import { pipe } from 'ramda';
|
import { pipe } from 'ramda';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { CreateVisit } from '../../visits/types';
|
import type { CreateVisit } from '../../visits/types';
|
||||||
import { MercureInfo } from '../reducers/mercureInfo';
|
import type { MercureInfo } from '../reducers/mercureInfo';
|
||||||
import { bindToMercureTopic } from './index';
|
import { bindToMercureTopic } from './index';
|
||||||
|
|
||||||
export interface MercureBoundProps {
|
export interface MercureBoundProps {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { EventSourcePolyfill as EventSource } from 'event-source-polyfill';
|
import { EventSourcePolyfill as EventSource } from 'event-source-polyfill';
|
||||||
import { MercureInfo } from '../reducers/mercureInfo';
|
import type { MercureInfo } from '../reducers/mercureInfo';
|
||||||
|
|
||||||
export const bindToMercureTopic = <T>(mercureInfo: MercureInfo, topics: string[], onMessage: (message: T) => void, onTokenExpired: () => void) => { // eslint-disable-line max-len
|
export const bindToMercureTopic = <T>(mercureInfo: MercureInfo, topics: string[], onMessage: (message: T) => void, onTokenExpired: () => void) => { // eslint-disable-line max-len
|
||||||
const { mercureHubUrl, token, loading, error } = mercureInfo;
|
const { mercureHubUrl, token, loading, error } = mercureInfo;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
import type { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
|
import type { ShlinkMercureInfo } from '../../api/types';
|
||||||
import { createAsyncThunk } from '../../utils/helpers/redux';
|
import { createAsyncThunk } from '../../utils/helpers/redux';
|
||||||
import { ShlinkMercureInfo } from '../../api/types';
|
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/mercure';
|
const REDUCER_PREFIX = 'shlink/mercure';
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import type Bottle from 'bottlejs';
|
||||||
import { prop } from 'ramda';
|
import { prop } from 'ramda';
|
||||||
import Bottle from 'bottlejs';
|
|
||||||
import { mercureInfoReducerCreator } from '../reducers/mercureInfo';
|
import { mercureInfoReducerCreator } from '../reducers/mercureInfo';
|
||||||
|
|
||||||
const provideServices = (bottle: Bottle) => {
|
export const provideServices = (bottle: Bottle) => {
|
||||||
// Reducer
|
// Reducer
|
||||||
bottle.serviceFactory('mercureInfoReducerCreator', mercureInfoReducerCreator, 'buildShlinkApiClient');
|
bottle.serviceFactory('mercureInfoReducerCreator', mercureInfoReducerCreator, 'buildShlinkApiClient');
|
||||||
bottle.serviceFactory('mercureInfoReducer', prop('reducer'), 'mercureInfoReducerCreator');
|
bottle.serviceFactory('mercureInfoReducer', prop('reducer'), 'mercureInfoReducerCreator');
|
||||||
|
@ -10,5 +10,3 @@ const provideServices = (bottle: Bottle) => {
|
||||||
// Actions
|
// Actions
|
||||||
bottle.serviceFactory('loadMercureInfo', prop('loadMercureInfo'), 'mercureInfoReducerCreator');
|
bottle.serviceFactory('loadMercureInfo', prop('loadMercureInfo'), 'mercureInfoReducerCreator');
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { IContainer } from 'bottlejs';
|
|
||||||
import { combineReducers } from '@reduxjs/toolkit';
|
import { combineReducers } from '@reduxjs/toolkit';
|
||||||
import { serversReducer } from '../servers/reducers/servers';
|
import type { IContainer } from 'bottlejs';
|
||||||
import { settingsReducer } from '../settings/reducers/settings';
|
|
||||||
import { appUpdatesReducer } from '../app/reducers/appUpdates';
|
import { appUpdatesReducer } from '../app/reducers/appUpdates';
|
||||||
import { sidebarReducer } from '../common/reducers/sidebar';
|
import { sidebarReducer } from '../common/reducers/sidebar';
|
||||||
import { ShlinkState } from '../container/types';
|
import type { ShlinkState } from '../container/types';
|
||||||
|
import { serversReducer } from '../servers/reducers/servers';
|
||||||
|
import { settingsReducer } from '../settings/reducers/settings';
|
||||||
|
|
||||||
export default (container: IContainer) => combineReducers<ShlinkState>({
|
export const initReducers = (container: IContainer) => combineReducers<ShlinkState>({
|
||||||
servers: serversReducer,
|
servers: serversReducer,
|
||||||
selectedServer: container.selectedServerReducer,
|
selectedServer: container.selectedServerReducer,
|
||||||
shortUrlsList: container.shortUrlsListReducer,
|
shortUrlsList: container.shortUrlsListReducer,
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { FC, useEffect, useState } from 'react';
|
import type { FC } from 'react';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { useEffect, useState } from 'react';
|
||||||
import { Button } from 'reactstrap';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Result } from '../utils/Result';
|
import { Button } from 'reactstrap';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import { NoMenuLayout } from '../common/NoMenuLayout';
|
import { NoMenuLayout } from '../common/NoMenuLayout';
|
||||||
import { TimeoutToggle, useGoBack, useToggle } from '../utils/helpers/hooks';
|
import type { TimeoutToggle } from '../utils/helpers/hooks';
|
||||||
import { ServerForm } from './helpers/ServerForm';
|
import { useGoBack, useToggle } from '../utils/helpers/hooks';
|
||||||
import { ImportServersBtnProps } from './helpers/ImportServersBtn';
|
import { Result } from '../utils/Result';
|
||||||
import { ServerData, ServersMap, ServerWithId } from './data';
|
import type { ServerData, ServersMap, ServerWithId } from './data';
|
||||||
import { DuplicatedServersModal } from './helpers/DuplicatedServersModal';
|
import { DuplicatedServersModal } from './helpers/DuplicatedServersModal';
|
||||||
|
import type { ImportServersBtnProps } from './helpers/ImportServersBtn';
|
||||||
|
import { ServerForm } from './helpers/ServerForm';
|
||||||
|
|
||||||
const SHOW_IMPORT_MSG_TIME = 4000;
|
const SHOW_IMPORT_MSG_TIME = 4000;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { FC, PropsWithChildren } from 'react';
|
|
||||||
import { faMinusCircle as deleteIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faMinusCircle as deleteIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
import { useToggle } from '../utils/helpers/hooks';
|
import { useToggle } from '../utils/helpers/hooks';
|
||||||
import { DeleteServerModalProps } from './DeleteServerModal';
|
import type { ServerWithId } from './data';
|
||||||
import { ServerWithId } from './data';
|
import type { DeleteServerModalProps } from './DeleteServerModal';
|
||||||
|
|
||||||
export type DeleteServerButtonProps = PropsWithChildren<{
|
export type DeleteServerButtonProps = PropsWithChildren<{
|
||||||
server: ServerWithId;
|
server: ServerWithId;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { FC, useRef } from 'react';
|
import type { FC } from 'react';
|
||||||
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
import { useRef } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { ServerWithId } from './data';
|
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
||||||
|
import type { ServerWithId } from './data';
|
||||||
|
|
||||||
export interface DeleteServerModalProps {
|
export interface DeleteServerModalProps {
|
||||||
server: ServerWithId;
|
server: ServerWithId;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { Button } from 'reactstrap';
|
import { Button } from 'reactstrap';
|
||||||
import { NoMenuLayout } from '../common/NoMenuLayout';
|
import { NoMenuLayout } from '../common/NoMenuLayout';
|
||||||
import { useGoBack, useParsedQuery } from '../utils/helpers/hooks';
|
import { useGoBack, useParsedQuery } from '../utils/helpers/hooks';
|
||||||
|
import type { ServerData } from './data';
|
||||||
|
import { isServerWithId } from './data';
|
||||||
import { ServerForm } from './helpers/ServerForm';
|
import { ServerForm } from './helpers/ServerForm';
|
||||||
import { withSelectedServer } from './helpers/withSelectedServer';
|
import { withSelectedServer } from './helpers/withSelectedServer';
|
||||||
import { isServerWithId, ServerData } from './data';
|
|
||||||
|
|
||||||
interface EditServerProps {
|
interface EditServerProps {
|
||||||
editServer: (serverId: string, serverData: ServerData) => void;
|
editServer: (serverId: string, serverData: ServerData) => void;
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import { FC, useEffect, useState } from 'react';
|
|
||||||
import { Button, Row } from 'reactstrap';
|
|
||||||
import { faFileDownload as exportIcon, faPlus as plusIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faFileDownload as exportIcon, faPlus as plusIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Button, Row } from 'reactstrap';
|
||||||
import { NoMenuLayout } from '../common/NoMenuLayout';
|
import { NoMenuLayout } from '../common/NoMenuLayout';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import type { TimeoutToggle } from '../utils/helpers/hooks';
|
||||||
import { SearchField } from '../utils/SearchField';
|
|
||||||
import { Result } from '../utils/Result';
|
import { Result } from '../utils/Result';
|
||||||
import { TimeoutToggle } from '../utils/helpers/hooks';
|
import { SearchField } from '../utils/SearchField';
|
||||||
import { ImportServersBtnProps } from './helpers/ImportServersBtn';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
import { ServersMap } from './data';
|
import type { ServersMap } from './data';
|
||||||
import { ManageServersRowProps } from './ManageServersRow';
|
import type { ImportServersBtnProps } from './helpers/ImportServersBtn';
|
||||||
import ServersExporter from './services/ServersExporter';
|
import type { ManageServersRowProps } from './ManageServersRow';
|
||||||
|
import type { ServersExporter } from './services/ServersExporter';
|
||||||
|
|
||||||
interface ManageServersProps {
|
interface ManageServersProps {
|
||||||
servers: ServersMap;
|
servers: ServersMap;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { FC } from 'react';
|
|
||||||
import { UncontrolledTooltip } from 'reactstrap';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faCheck as checkIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faCheck as checkIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { ServerWithId } from './data';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { ManageServersRowDropdownProps } from './ManageServersRowDropdown';
|
import type { FC } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { UncontrolledTooltip } from 'reactstrap';
|
||||||
|
import type { ServerWithId } from './data';
|
||||||
|
import type { ManageServersRowDropdownProps } from './ManageServersRowDropdown';
|
||||||
|
|
||||||
export interface ManageServersRowProps {
|
export interface ManageServersRowProps {
|
||||||
server: ServerWithId;
|
server: ServerWithId;
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { FC } from 'react';
|
import { faCircle as toggleOnIcon } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { DropdownItem } from 'reactstrap';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import {
|
import {
|
||||||
faBan as toggleOffIcon,
|
faBan as toggleOffIcon,
|
||||||
faEdit as editIcon,
|
faEdit as editIcon,
|
||||||
faMinusCircle as deleteIcon,
|
faMinusCircle as deleteIcon,
|
||||||
faPlug as connectIcon,
|
faPlug as connectIcon,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faCircle as toggleOnIcon } from '@fortawesome/free-regular-svg-icons';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { DropdownItem } from 'reactstrap';
|
||||||
import { DropdownBtnMenu } from '../utils/DropdownBtnMenu';
|
import { DropdownBtnMenu } from '../utils/DropdownBtnMenu';
|
||||||
import { useToggle } from '../utils/helpers/hooks';
|
import { useToggle } from '../utils/helpers/hooks';
|
||||||
import { DeleteServerModalProps } from './DeleteServerModal';
|
import type { ServerWithId } from './data';
|
||||||
import { ServerWithId } from './data';
|
import type { DeleteServerModalProps } from './DeleteServerModal';
|
||||||
|
|
||||||
export interface ManageServersRowDropdownProps {
|
export interface ManageServersRowDropdownProps {
|
||||||
server: ServerWithId;
|
server: ServerWithId;
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import { FC, useEffect } from 'react';
|
import type { FC } from 'react';
|
||||||
import { Card, CardBody, CardHeader, Row } from 'reactstrap';
|
import { useEffect } from 'react';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { ITEMS_IN_OVERVIEW_PAGE, ShortUrlsList as ShortUrlsListState } from '../short-urls/reducers/shortUrlsList';
|
import { Card, CardBody, CardHeader, Row } from 'reactstrap';
|
||||||
import { prettify } from '../utils/helpers/numbers';
|
import type { ShlinkShortUrlsListParams } from '../api/types';
|
||||||
import { TagsList } from '../tags/reducers/tagsList';
|
|
||||||
import { ShortUrlsTableType } from '../short-urls/ShortUrlsTable';
|
|
||||||
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
||||||
import { CreateShortUrlProps } from '../short-urls/CreateShortUrl';
|
|
||||||
import { VisitsOverview } from '../visits/reducers/visitsOverview';
|
|
||||||
import { Topics } from '../mercure/helpers/Topics';
|
import { Topics } from '../mercure/helpers/Topics';
|
||||||
import { ShlinkShortUrlsListParams } from '../api/types';
|
import type { CreateShortUrlProps } from '../short-urls/CreateShortUrl';
|
||||||
|
import type { ShortUrlsList as ShortUrlsListState } from '../short-urls/reducers/shortUrlsList';
|
||||||
|
import { ITEMS_IN_OVERVIEW_PAGE } from '../short-urls/reducers/shortUrlsList';
|
||||||
|
import type { ShortUrlsTableType } from '../short-urls/ShortUrlsTable';
|
||||||
|
import type { TagsList } from '../tags/reducers/tagsList';
|
||||||
import { supportsNonOrphanVisits } from '../utils/helpers/features';
|
import { supportsNonOrphanVisits } from '../utils/helpers/features';
|
||||||
import { getServerId, SelectedServer } from './data';
|
import { prettify } from '../utils/helpers/numbers';
|
||||||
|
import type { VisitsOverview } from '../visits/reducers/visitsOverview';
|
||||||
|
import type { SelectedServer } from './data';
|
||||||
|
import { getServerId } from './data';
|
||||||
import { HighlightCard } from './helpers/HighlightCard';
|
import { HighlightCard } from './helpers/HighlightCard';
|
||||||
|
|
||||||
interface OverviewConnectProps {
|
interface OverviewConnectProps {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { isEmpty, values } from 'ramda';
|
|
||||||
import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { faPlus as plusIcon, faServer as serverIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faPlus as plusIcon, faServer as serverIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { getServerId, SelectedServer, ServersMap } from './data';
|
import { isEmpty, values } from 'ramda';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';
|
||||||
|
import type { SelectedServer, ServersMap } from './data';
|
||||||
|
import { getServerId } from './data';
|
||||||
|
|
||||||
export interface ServersDropdownProps {
|
export interface ServersDropdownProps {
|
||||||
servers: ServersMap;
|
servers: ServersMap;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { FC, PropsWithChildren } from 'react';
|
|
||||||
import { ListGroup, ListGroupItem } from 'reactstrap';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { ServerWithId } from './data';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { ListGroup, ListGroupItem } from 'reactstrap';
|
||||||
|
import type { ServerWithId } from './data';
|
||||||
import './ServersListGroup.scss';
|
import './ServersListGroup.scss';
|
||||||
|
|
||||||
type ServersListGroupProps = PropsWithChildren<{
|
type ServersListGroupProps = PropsWithChildren<{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { omit } from 'ramda';
|
import { omit } from 'ramda';
|
||||||
import { SemVer } from '../../utils/helpers/version';
|
import type { SemVer } from '../../utils/helpers/version';
|
||||||
|
|
||||||
export interface ServerData {
|
export interface ServerData {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { FC, Fragment } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import { Fragment } from 'react';
|
||||||
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
||||||
import { ServerData } from '../data';
|
import type { ServerData } from '../data';
|
||||||
|
|
||||||
interface DuplicatedServersModalProps {
|
interface DuplicatedServersModalProps {
|
||||||
duplicatedServers: ServerData[];
|
duplicatedServers: ServerData[];
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { FC, PropsWithChildren } from 'react';
|
|
||||||
import { Card, CardText, CardTitle } from 'reactstrap';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { faArrowAltCircleRight as linkIcon } from '@fortawesome/free-regular-svg-icons';
|
import { faArrowAltCircleRight as linkIcon } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { FC, PropsWithChildren } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Card, CardText, CardTitle } from 'reactstrap';
|
||||||
import './HighlightCard.scss';
|
import './HighlightCard.scss';
|
||||||
|
|
||||||
export type HighlightCardProps = PropsWithChildren<{
|
export type HighlightCardProps = PropsWithChildren<{
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { useRef, ChangeEvent, useState, useEffect, FC, PropsWithChildren } from 'react';
|
|
||||||
import { Button, UncontrolledTooltip } from 'reactstrap';
|
|
||||||
import { complement, pipe } from 'ramda';
|
|
||||||
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { useToggle } from '../../utils/helpers/hooks';
|
import { complement, pipe } from 'ramda';
|
||||||
import { mutableRefToElementRef } from '../../utils/helpers/components';
|
import type { ChangeEvent, FC, PropsWithChildren } from 'react';
|
||||||
import { ServersImporter } from '../services/ServersImporter';
|
import { useEffect, useState } from 'react';
|
||||||
import { ServerData, ServersMap } from '../data';
|
import { Button, UncontrolledTooltip } from 'reactstrap';
|
||||||
|
import { useElementRef, useToggle } from '../../utils/helpers/hooks';
|
||||||
|
import type { ServerData, ServersMap } from '../data';
|
||||||
|
import type { ServersImporter } from '../services/ServersImporter';
|
||||||
import { DuplicatedServersModal } from './DuplicatedServersModal';
|
import { DuplicatedServersModal } from './DuplicatedServersModal';
|
||||||
import './ImportServersBtn.scss';
|
import './ImportServersBtn.scss';
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC
|
||||||
tooltipPlacement = 'bottom',
|
tooltipPlacement = 'bottom',
|
||||||
className = '',
|
className = '',
|
||||||
}) => {
|
}) => {
|
||||||
const ref = useRef<HTMLInputElement>();
|
const ref = useElementRef<HTMLInputElement>();
|
||||||
const [serversToCreate, setServersToCreate] = useState<ServerData[] | undefined>();
|
const [serversToCreate, setServersToCreate] = useState<ServerData[] | undefined>();
|
||||||
const [duplicatedServers, setDuplicatedServers] = useState<ServerData[]>([]);
|
const [duplicatedServers, setDuplicatedServers] = useState<ServerData[]>([]);
|
||||||
const [isModalOpen,, showModal, hideModal] = useToggle();
|
const [isModalOpen,, showModal, hideModal] = useToggle();
|
||||||
|
@ -79,7 +79,7 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC
|
||||||
type="file"
|
type="file"
|
||||||
accept="text/csv"
|
accept="text/csv"
|
||||||
className="import-servers-btn__csv-select"
|
className="import-servers-btn__csv-select"
|
||||||
ref={mutableRefToElementRef(ref)}
|
ref={ref}
|
||||||
onChange={onFile}
|
onChange={onFile}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Message } from '../../utils/Message';
|
|
||||||
import { ServersListGroup } from '../ServersListGroup';
|
|
||||||
import { DeleteServerButtonProps } from '../DeleteServerButton';
|
|
||||||
import { isServerWithId, SelectedServer, ServersMap } from '../data';
|
|
||||||
import { NoMenuLayout } from '../../common/NoMenuLayout';
|
import { NoMenuLayout } from '../../common/NoMenuLayout';
|
||||||
|
import { Message } from '../../utils/Message';
|
||||||
|
import type { SelectedServer, ServersMap } from '../data';
|
||||||
|
import { isServerWithId } from '../data';
|
||||||
|
import type { DeleteServerButtonProps } from '../DeleteServerButton';
|
||||||
|
import { ServersListGroup } from '../ServersListGroup';
|
||||||
import './ServerError.scss';
|
import './ServerError.scss';
|
||||||
|
|
||||||
interface ServerErrorProps {
|
interface ServerErrorProps {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { FC, PropsWithChildren, ReactNode, useEffect, useState } from 'react';
|
import type { FC, PropsWithChildren, ReactNode } from 'react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { InputFormGroup } from '../../utils/forms/InputFormGroup';
|
import { InputFormGroup } from '../../utils/forms/InputFormGroup';
|
||||||
import { handleEventPreventingDefault } from '../../utils/utils';
|
|
||||||
import { ServerData } from '../data';
|
|
||||||
import { SimpleCard } from '../../utils/SimpleCard';
|
import { SimpleCard } from '../../utils/SimpleCard';
|
||||||
|
import { handleEventPreventingDefault } from '../../utils/utils';
|
||||||
|
import type { ServerData } from '../data';
|
||||||
|
|
||||||
type ServerFormProps = PropsWithChildren<{
|
type ServerFormProps = PropsWithChildren<{
|
||||||
onSubmit: (server: ServerData) => void;
|
onSubmit: (server: ServerData) => void;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { FC, useEffect } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { Message } from '../../utils/Message';
|
|
||||||
import { isNotFoundServer, SelectedServer } from '../data';
|
|
||||||
import { NoMenuLayout } from '../../common/NoMenuLayout';
|
import { NoMenuLayout } from '../../common/NoMenuLayout';
|
||||||
|
import { Message } from '../../utils/Message';
|
||||||
|
import type { SelectedServer } from '../data';
|
||||||
|
import { isNotFoundServer } from '../data';
|
||||||
|
|
||||||
interface WithSelectedServerProps {
|
interface WithSelectedServerProps {
|
||||||
selectServer: (serverId: string) => void;
|
selectServer: (serverId: string) => void;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { FC, useEffect } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
interface WithoutSelectedServerProps {
|
interface WithoutSelectedServerProps {
|
||||||
resetSelectedServer: Function;
|
resetSelectedServer: Function;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import pack from '../../../package.json';
|
import pack from '../../../package.json';
|
||||||
import { hasServerData, ServerData } from '../data';
|
import type { HttpClient } from '../../common/services/HttpClient';
|
||||||
import { createServers } from './servers';
|
|
||||||
import { createAsyncThunk } from '../../utils/helpers/redux';
|
import { createAsyncThunk } from '../../utils/helpers/redux';
|
||||||
import { HttpClient } from '../../common/services/HttpClient';
|
import type { ServerData } from '../data';
|
||||||
|
import { hasServerData } from '../data';
|
||||||
|
import { createServers } from './servers';
|
||||||
|
|
||||||
const responseToServersList = (data: any): ServerData[] => (Array.isArray(data) ? data.filter(hasServerData) : []);
|
const responseToServersList = (data: any): ServerData[] => (Array.isArray(data) ? data.filter(hasServerData) : []);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { createAction, createListenerMiddleware, createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
|
import { createAction, createListenerMiddleware, createSlice } from '@reduxjs/toolkit';
|
||||||
import { memoizeWith, pipe } from 'ramda';
|
import { memoizeWith, pipe } from 'ramda';
|
||||||
import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';
|
import type { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { isReachableServer, SelectedServer, ServerWithId } from '../data';
|
import type { ShlinkHealth } from '../../api/types';
|
||||||
import { ShlinkHealth } from '../../api/types';
|
|
||||||
import { createAsyncThunk } from '../../utils/helpers/redux';
|
import { createAsyncThunk } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';
|
||||||
|
import type { SelectedServer, ServerWithId } from '../data';
|
||||||
|
import { isReachableServer } from '../data';
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/selectedServer';
|
const REDUCER_PREFIX = 'shlink/selectedServer';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import { assoc, dissoc, fromPairs, map, pipe, reduce, toPairs } from 'ramda';
|
import { assoc, dissoc, fromPairs, map, pipe, reduce, toPairs } from 'ramda';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { ServerData, ServersMap, ServerWithId } from '../data';
|
import type { ServerData, ServersMap, ServerWithId } from '../data';
|
||||||
|
|
||||||
interface EditServer {
|
interface EditServer {
|
||||||
serverId: string;
|
serverId: string;
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { values } from 'ramda';
|
import { values } from 'ramda';
|
||||||
import { LocalStorage } from '../../utils/services/LocalStorage';
|
import type { JsonToCsv } from '../../utils/helpers/csvjson';
|
||||||
import { ServersMap, serverWithIdToServerData } from '../data';
|
|
||||||
import { saveCsv } from '../../utils/helpers/files';
|
import { saveCsv } from '../../utils/helpers/files';
|
||||||
import { JsonToCsv } from '../../utils/helpers/csvjson';
|
import type { LocalStorage } from '../../utils/services/LocalStorage';
|
||||||
|
import type { ServersMap } from '../data';
|
||||||
|
import { serverWithIdToServerData } from '../data';
|
||||||
|
|
||||||
const SERVERS_FILENAME = 'shlink-servers.csv';
|
const SERVERS_FILENAME = 'shlink-servers.csv';
|
||||||
|
|
||||||
export default class ServersExporter {
|
export class ServersExporter {
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly storage: LocalStorage,
|
private readonly storage: LocalStorage,
|
||||||
private readonly window: Window,
|
private readonly window: Window,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ServerData } from '../data';
|
import type { CsvToJson } from '../../utils/helpers/csvjson';
|
||||||
import { CsvToJson } from '../../utils/helpers/csvjson';
|
import type { ServerData } from '../data';
|
||||||
|
|
||||||
const validateServer = (server: any): server is ServerData =>
|
const validateServer = (server: any): server is ServerData =>
|
||||||
typeof server.url === 'string' && typeof server.apiKey === 'string' && typeof server.name === 'string';
|
typeof server.url === 'string' && typeof server.apiKey === 'string' && typeof server.name === 'string';
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
|
import type Bottle from 'bottlejs';
|
||||||
import { prop } from 'ramda';
|
import { prop } from 'ramda';
|
||||||
import Bottle from 'bottlejs';
|
import type { ConnectDecorator } from '../../container/types';
|
||||||
import { CreateServer } from '../CreateServer';
|
import { CreateServer } from '../CreateServer';
|
||||||
import { ServersDropdown } from '../ServersDropdown';
|
|
||||||
import { DeleteServerModal } from '../DeleteServerModal';
|
|
||||||
import { DeleteServerButton } from '../DeleteServerButton';
|
import { DeleteServerButton } from '../DeleteServerButton';
|
||||||
|
import { DeleteServerModal } from '../DeleteServerModal';
|
||||||
import { EditServer } from '../EditServer';
|
import { EditServer } from '../EditServer';
|
||||||
import { ImportServersBtn } from '../helpers/ImportServersBtn';
|
import { ImportServersBtn } from '../helpers/ImportServersBtn';
|
||||||
|
import { ServerError } from '../helpers/ServerError';
|
||||||
|
import { withoutSelectedServer } from '../helpers/withoutSelectedServer';
|
||||||
|
import { ManageServers } from '../ManageServers';
|
||||||
|
import { ManageServersRow } from '../ManageServersRow';
|
||||||
|
import { ManageServersRowDropdown } from '../ManageServersRowDropdown';
|
||||||
|
import { Overview } from '../Overview';
|
||||||
|
import { fetchServers } from '../reducers/remoteServers';
|
||||||
import {
|
import {
|
||||||
resetSelectedServer,
|
resetSelectedServer,
|
||||||
selectedServerReducerCreator,
|
selectedServerReducerCreator,
|
||||||
|
@ -13,18 +20,11 @@ import {
|
||||||
selectServerListener,
|
selectServerListener,
|
||||||
} from '../reducers/selectedServer';
|
} from '../reducers/selectedServer';
|
||||||
import { createServers, deleteServer, editServer, setAutoConnect } from '../reducers/servers';
|
import { createServers, deleteServer, editServer, setAutoConnect } from '../reducers/servers';
|
||||||
import { fetchServers } from '../reducers/remoteServers';
|
import { ServersDropdown } from '../ServersDropdown';
|
||||||
import { ServerError } from '../helpers/ServerError';
|
import { ServersExporter } from './ServersExporter';
|
||||||
import { ConnectDecorator } from '../../container/types';
|
|
||||||
import { withoutSelectedServer } from '../helpers/withoutSelectedServer';
|
|
||||||
import { Overview } from '../Overview';
|
|
||||||
import { ManageServers } from '../ManageServers';
|
|
||||||
import { ManageServersRow } from '../ManageServersRow';
|
|
||||||
import { ManageServersRowDropdown } from '../ManageServersRowDropdown';
|
|
||||||
import { ServersImporter } from './ServersImporter';
|
import { ServersImporter } from './ServersImporter';
|
||||||
import ServersExporter from './ServersExporter';
|
|
||||||
|
|
||||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
// Components
|
// Components
|
||||||
bottle.serviceFactory(
|
bottle.serviceFactory(
|
||||||
'ManageServers',
|
'ManageServers',
|
||||||
|
@ -89,5 +89,3 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('selectedServerReducerCreator', selectedServerReducerCreator, 'selectServer');
|
bottle.serviceFactory('selectedServerReducerCreator', selectedServerReducerCreator, 'selectServer');
|
||||||
bottle.serviceFactory('selectedServerReducer', prop('reducer'), 'selectedServerReducerCreator');
|
bottle.serviceFactory('selectedServerReducer', prop('reducer'), 'selectedServerReducerCreator');
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { FormGroup, Input } from 'reactstrap';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
import { FormGroup, Input } from 'reactstrap';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
|
||||||
import { FormText } from '../utils/forms/FormText';
|
import { FormText } from '../utils/forms/FormText';
|
||||||
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
||||||
import { Settings } from './reducers/settings';
|
|
||||||
import { useDomId } from '../utils/helpers/hooks';
|
import { useDomId } from '../utils/helpers/hooks';
|
||||||
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
||||||
|
import type { Settings } from './reducers/settings';
|
||||||
|
|
||||||
interface RealTimeUpdatesProps {
|
interface RealTimeUpdatesProps {
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { FC, ReactNode } from 'react';
|
import type { FC, ReactNode } from 'react';
|
||||||
import { Navigate, Routes, Route } from 'react-router-dom';
|
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||||
import { NoMenuLayout } from '../common/NoMenuLayout';
|
import { NoMenuLayout } from '../common/NoMenuLayout';
|
||||||
import { NavPillItem, NavPills } from '../utils/NavPills';
|
import { NavPillItem, NavPills } from '../utils/NavPills';
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { FC, ReactNode } from 'react';
|
import type { FC, ReactNode } from 'react';
|
||||||
import { DropdownItem, FormGroup } from 'reactstrap';
|
import { DropdownItem, FormGroup } from 'reactstrap';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
|
||||||
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
|
||||||
import { DropdownBtn } from '../utils/DropdownBtn';
|
import { DropdownBtn } from '../utils/DropdownBtn';
|
||||||
import { FormText } from '../utils/forms/FormText';
|
import { FormText } from '../utils/forms/FormText';
|
||||||
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
||||||
import { Settings, ShortUrlCreationSettings as ShortUrlsSettings, TagFilteringMode } from './reducers/settings';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
||||||
|
import type { Settings, ShortUrlCreationSettings as ShortUrlsSettings, TagFilteringMode } from './reducers/settings';
|
||||||
|
|
||||||
interface ShortUrlCreationProps {
|
interface ShortUrlCreationProps {
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { OrderingDropdown } from '../utils/OrderingDropdown';
|
|
||||||
import { SHORT_URLS_ORDERABLE_FIELDS } from '../short-urls/data';
|
import { SHORT_URLS_ORDERABLE_FIELDS } from '../short-urls/data';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
|
||||||
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
||||||
import { DEFAULT_SHORT_URLS_ORDERING, Settings, ShortUrlsListSettings as ShortUrlsSettings } from './reducers/settings';
|
import { OrderingDropdown } from '../utils/OrderingDropdown';
|
||||||
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
import type { Settings, ShortUrlsListSettings as ShortUrlsSettings } from './reducers/settings';
|
||||||
|
import { DEFAULT_SHORT_URLS_ORDERING } from './reducers/settings';
|
||||||
|
|
||||||
interface ShortUrlsListSettingsProps {
|
interface ShortUrlsListSettingsProps {
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
|
||||||
import { OrderingDropdown } from '../utils/OrderingDropdown';
|
|
||||||
import { TAGS_ORDERABLE_FIELDS } from '../tags/data/TagsListChildrenProps';
|
import { TAGS_ORDERABLE_FIELDS } from '../tags/data/TagsListChildrenProps';
|
||||||
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
||||||
import { Settings, TagsSettings as TagsSettingsOptions } from './reducers/settings';
|
import { OrderingDropdown } from '../utils/OrderingDropdown';
|
||||||
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
import type { Settings, TagsSettings as TagsSettingsOptions } from './reducers/settings';
|
||||||
|
|
||||||
interface TagsProps {
|
interface TagsProps {
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { FC } from 'react';
|
import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faSun, faMoon } from '@fortawesome/free-solid-svg-icons';
|
import type { FC } from 'react';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
import type { Theme } from '../utils/theme';
|
||||||
|
import { changeThemeInMarkup } from '../utils/theme';
|
||||||
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
||||||
import { changeThemeInMarkup, Theme } from '../utils/theme';
|
import type { Settings, UiSettings } from './reducers/settings';
|
||||||
import { Settings, UiSettings } from './reducers/settings';
|
|
||||||
import './UserInterfaceSettings.scss';
|
import './UserInterfaceSettings.scss';
|
||||||
|
|
||||||
interface UserInterfaceProps {
|
interface UserInterfaceProps {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { FormGroup } from 'reactstrap';
|
import { FormGroup } from 'reactstrap';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
|
||||||
import { DateIntervalSelector } from '../utils/dates/DateIntervalSelector';
|
import { DateIntervalSelector } from '../utils/dates/DateIntervalSelector';
|
||||||
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
|
||||||
import { Settings, VisitsSettings as VisitsSettingsConfig } from './reducers/settings';
|
|
||||||
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
|
||||||
import { FormText } from '../utils/forms/FormText';
|
import { FormText } from '../utils/forms/FormText';
|
||||||
import { DateInterval } from '../utils/helpers/dateIntervals';
|
import { LabeledFormGroup } from '../utils/forms/LabeledFormGroup';
|
||||||
|
import type { DateInterval } from '../utils/helpers/dateIntervals';
|
||||||
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
|
import { ToggleSwitch } from '../utils/ToggleSwitch';
|
||||||
|
import type { Settings, VisitsSettings as VisitsSettingsConfig } from './reducers/settings';
|
||||||
|
|
||||||
interface VisitsProps {
|
interface VisitsProps {
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ShlinkState } from '../../container/types';
|
import type { ShlinkState } from '../../container/types';
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
export const migrateDeprecatedSettings = (state: Partial<ShlinkState>): Partial<ShlinkState> => {
|
export const migrateDeprecatedSettings = (state: Partial<ShlinkState>): Partial<ShlinkState> => {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { createSlice, PayloadAction, PrepareAction } from '@reduxjs/toolkit';
|
import type { PayloadAction, PrepareAction } from '@reduxjs/toolkit';
|
||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import { mergeDeepRight } from 'ramda';
|
import { mergeDeepRight } from 'ramda';
|
||||||
import { Theme } from '../../utils/theme';
|
import type { ShortUrlsOrder } from '../../short-urls/data';
|
||||||
import { DateInterval } from '../../utils/helpers/dateIntervals';
|
import type { TagsOrder } from '../../tags/data/TagsListChildrenProps';
|
||||||
import { TagsOrder } from '../../tags/data/TagsListChildrenProps';
|
import type { DateInterval } from '../../utils/helpers/dateIntervals';
|
||||||
import { ShortUrlsOrder } from '../../short-urls/data';
|
import type { Theme } from '../../utils/theme';
|
||||||
|
|
||||||
export const DEFAULT_SHORT_URLS_ORDERING: ShortUrlsOrder = {
|
export const DEFAULT_SHORT_URLS_ORDERING: ShortUrlsOrder = {
|
||||||
field: 'dateCreated',
|
field: 'dateCreated',
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Bottle from 'bottlejs';
|
import type Bottle from 'bottlejs';
|
||||||
|
import type { ConnectDecorator } from '../../container/types';
|
||||||
|
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
|
||||||
import { RealTimeUpdatesSettings } from '../RealTimeUpdatesSettings';
|
import { RealTimeUpdatesSettings } from '../RealTimeUpdatesSettings';
|
||||||
import { Settings } from '../Settings';
|
|
||||||
import {
|
import {
|
||||||
setRealTimeUpdatesInterval,
|
setRealTimeUpdatesInterval,
|
||||||
setShortUrlCreationSettings,
|
setShortUrlCreationSettings,
|
||||||
|
@ -10,15 +11,14 @@ import {
|
||||||
setVisitsSettings,
|
setVisitsSettings,
|
||||||
toggleRealTimeUpdates,
|
toggleRealTimeUpdates,
|
||||||
} from '../reducers/settings';
|
} from '../reducers/settings';
|
||||||
import { ConnectDecorator } from '../../container/types';
|
import { Settings } from '../Settings';
|
||||||
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
|
|
||||||
import { ShortUrlCreationSettings } from '../ShortUrlCreationSettings';
|
import { ShortUrlCreationSettings } from '../ShortUrlCreationSettings';
|
||||||
|
import { ShortUrlsListSettings } from '../ShortUrlsListSettings';
|
||||||
|
import { TagsSettings } from '../TagsSettings';
|
||||||
import { UserInterfaceSettings } from '../UserInterfaceSettings';
|
import { UserInterfaceSettings } from '../UserInterfaceSettings';
|
||||||
import { VisitsSettings } from '../VisitsSettings';
|
import { VisitsSettings } from '../VisitsSettings';
|
||||||
import { TagsSettings } from '../TagsSettings';
|
|
||||||
import { ShortUrlsListSettings } from '../ShortUrlsListSettings';
|
|
||||||
|
|
||||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
// Components
|
// Components
|
||||||
bottle.serviceFactory(
|
bottle.serviceFactory(
|
||||||
'Settings',
|
'Settings',
|
||||||
|
@ -63,5 +63,3 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('setVisitsSettings', () => setVisitsSettings);
|
bottle.serviceFactory('setVisitsSettings', () => setVisitsSettings);
|
||||||
bottle.serviceFactory('setTagsSettings', () => setTagsSettings);
|
bottle.serviceFactory('setTagsSettings', () => setTagsSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { FC, useMemo } from 'react';
|
import type { FC } from 'react';
|
||||||
import { SelectedServer } from '../servers/data';
|
import { useMemo } from 'react';
|
||||||
import { Settings, ShortUrlCreationSettings } from '../settings/reducers/settings';
|
import type { SelectedServer } from '../servers/data';
|
||||||
import { ShortUrlData } from './data';
|
import type { Settings, ShortUrlCreationSettings } from '../settings/reducers/settings';
|
||||||
import { ShortUrlCreation } from './reducers/shortUrlCreation';
|
import type { ShortUrlData } from './data';
|
||||||
import { CreateShortUrlResultProps } from './helpers/CreateShortUrlResult';
|
import type { CreateShortUrlResultProps } from './helpers/CreateShortUrlResult';
|
||||||
import { ShortUrlFormProps } from './ShortUrlForm';
|
import type { ShortUrlCreation } from './reducers/shortUrlCreation';
|
||||||
|
import type { ShortUrlFormProps } from './ShortUrlForm';
|
||||||
|
|
||||||
export interface CreateShortUrlProps {
|
export interface CreateShortUrlProps {
|
||||||
basicMode?: boolean;
|
basicMode?: boolean;
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
import { FC, useEffect, useMemo } from 'react';
|
|
||||||
import { Button, Card } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
|
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { useEffect, useMemo } from 'react';
|
||||||
import { ExternalLink } from 'react-external-link';
|
import { ExternalLink } from 'react-external-link';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { SelectedServer } from '../servers/data';
|
import { Button, Card } from 'reactstrap';
|
||||||
import { Settings } from '../settings/reducers/settings';
|
import { ShlinkApiError } from '../api/ShlinkApiError';
|
||||||
import { ShortUrlIdentifier } from './data';
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
import type { Settings } from '../settings/reducers/settings';
|
||||||
|
import { useGoBack } from '../utils/helpers/hooks';
|
||||||
import { parseQuery } from '../utils/helpers/query';
|
import { parseQuery } from '../utils/helpers/query';
|
||||||
import { Message } from '../utils/Message';
|
import { Message } from '../utils/Message';
|
||||||
import { Result } from '../utils/Result';
|
import { Result } from '../utils/Result';
|
||||||
import { ShlinkApiError } from '../api/ShlinkApiError';
|
import type { ShortUrlIdentifier } from './data';
|
||||||
import { useGoBack } from '../utils/helpers/hooks';
|
|
||||||
import { ShortUrlFormProps } from './ShortUrlForm';
|
|
||||||
import { ShortUrlDetail } from './reducers/shortUrlDetail';
|
|
||||||
import { EditShortUrl as EditShortUrlInfo, ShortUrlEdition } from './reducers/shortUrlEdition';
|
|
||||||
import { shortUrlDataFromShortUrl, urlDecodeShortCode } from './helpers';
|
import { shortUrlDataFromShortUrl, urlDecodeShortCode } from './helpers';
|
||||||
|
import type { ShortUrlDetail } from './reducers/shortUrlDetail';
|
||||||
|
import type { EditShortUrl as EditShortUrlInfo, ShortUrlEdition } from './reducers/shortUrlEdition';
|
||||||
|
import type { ShortUrlFormProps } from './ShortUrlForm';
|
||||||
|
|
||||||
interface EditShortUrlConnectProps {
|
interface EditShortUrlConnectProps {
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
|
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
|
||||||
|
import type { ShlinkPaginator } from '../api/types';
|
||||||
|
import type {
|
||||||
|
NumberOrEllipsis } from '../utils/helpers/pagination';
|
||||||
import {
|
import {
|
||||||
pageIsEllipsis,
|
|
||||||
keyForPage,
|
keyForPage,
|
||||||
progressivePagination,
|
pageIsEllipsis,
|
||||||
prettifyPageNumber,
|
prettifyPageNumber,
|
||||||
NumberOrEllipsis,
|
progressivePagination,
|
||||||
} from '../utils/helpers/pagination';
|
} from '../utils/helpers/pagination';
|
||||||
import { ShlinkPaginator } from '../api/types';
|
|
||||||
|
|
||||||
interface PaginatorProps {
|
interface PaginatorProps {
|
||||||
paginator?: ShlinkPaginator;
|
paginator?: ShlinkPaginator;
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
import { FC, useEffect, useState } from 'react';
|
|
||||||
import { InputType } from 'reactstrap/types/lib/Input';
|
|
||||||
import { Button, FormGroup, Input, Row } from 'reactstrap';
|
|
||||||
import { cond, isEmpty, pipe, replace, trim, T } from 'ramda';
|
|
||||||
import { parseISO } from 'date-fns';
|
import { parseISO } from 'date-fns';
|
||||||
import { DateTimeInput, DateTimeInputProps } from '../utils/dates/DateTimeInput';
|
import { cond, isEmpty, pipe, replace, T, trim } from 'ramda';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Button, FormGroup, Input, Row } from 'reactstrap';
|
||||||
|
import type { InputType } from 'reactstrap/types/lib/Input';
|
||||||
|
import type { DomainSelectorProps } from '../domains/DomainSelector';
|
||||||
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
import type { TagsSelectorProps } from '../tags/helpers/TagsSelector';
|
||||||
|
import { Checkbox } from '../utils/Checkbox';
|
||||||
|
import type { DateTimeInputProps } from '../utils/dates/DateTimeInput';
|
||||||
|
import { DateTimeInput } from '../utils/dates/DateTimeInput';
|
||||||
|
import { formatIsoDate } from '../utils/helpers/date';
|
||||||
import { supportsForwardQuery } from '../utils/helpers/features';
|
import { supportsForwardQuery } from '../utils/helpers/features';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
import { handleEventPreventingDefault, hasValue, OptionalString } from '../utils/utils';
|
import type { OptionalString } from '../utils/utils';
|
||||||
import { Checkbox } from '../utils/Checkbox';
|
import { handleEventPreventingDefault, hasValue } from '../utils/utils';
|
||||||
import { SelectedServer } from '../servers/data';
|
import type { ShortUrlData } from './data';
|
||||||
import { TagsSelectorProps } from '../tags/helpers/TagsSelector';
|
|
||||||
import { DomainSelectorProps } from '../domains/DomainSelector';
|
|
||||||
import { formatIsoDate } from '../utils/helpers/date';
|
|
||||||
import { UseExistingIfFoundInfoIcon } from './UseExistingIfFoundInfoIcon';
|
|
||||||
import { ShortUrlData } from './data';
|
|
||||||
import { ShortUrlFormCheckboxGroup } from './helpers/ShortUrlFormCheckboxGroup';
|
import { ShortUrlFormCheckboxGroup } from './helpers/ShortUrlFormCheckboxGroup';
|
||||||
|
import { UseExistingIfFoundInfoIcon } from './UseExistingIfFoundInfoIcon';
|
||||||
import './ShortUrlForm.scss';
|
import './ShortUrlForm.scss';
|
||||||
|
|
||||||
export type Mode = 'create' | 'create-basic' | 'edit';
|
export type Mode = 'create' | 'create-basic' | 'edit';
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
import { FC } from 'react';
|
|
||||||
import { isEmpty, pipe } from 'ramda';
|
|
||||||
import { Button, InputGroup, Row, UncontrolledTooltip } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faTag, faTags } from '@fortawesome/free-solid-svg-icons';
|
import { faTag, faTags } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { SearchField } from '../utils/SearchField';
|
import { isEmpty, pipe } from 'ramda';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { Button, InputGroup, Row, UncontrolledTooltip } from 'reactstrap';
|
||||||
|
import type { SelectedServer } from '../servers/data';
|
||||||
|
import type { Settings } from '../settings/reducers/settings';
|
||||||
|
import type { TagsSelectorProps } from '../tags/helpers/TagsSelector';
|
||||||
import { DateRangeSelector } from '../utils/dates/DateRangeSelector';
|
import { DateRangeSelector } from '../utils/dates/DateRangeSelector';
|
||||||
import { formatIsoDate } from '../utils/helpers/date';
|
import { formatIsoDate } from '../utils/helpers/date';
|
||||||
import { DateRange, datesToDateRange } from '../utils/helpers/dateIntervals';
|
import type { DateRange } from '../utils/helpers/dateIntervals';
|
||||||
|
import { datesToDateRange } from '../utils/helpers/dateIntervals';
|
||||||
import { supportsAllTagsFiltering, supportsFilterDisabledUrls } from '../utils/helpers/features';
|
import { supportsAllTagsFiltering, supportsFilterDisabledUrls } from '../utils/helpers/features';
|
||||||
import { SelectedServer } from '../servers/data';
|
import type { OrderDir } from '../utils/helpers/ordering';
|
||||||
import { OrderDir } from '../utils/helpers/ordering';
|
|
||||||
import { OrderingDropdown } from '../utils/OrderingDropdown';
|
import { OrderingDropdown } from '../utils/OrderingDropdown';
|
||||||
|
import { SearchField } from '../utils/SearchField';
|
||||||
|
import type { ShortUrlsOrder, ShortUrlsOrderableFields } from './data';
|
||||||
|
import { SHORT_URLS_ORDERABLE_FIELDS } from './data';
|
||||||
|
import type { ExportShortUrlsBtnProps } from './helpers/ExportShortUrlsBtn';
|
||||||
import { useShortUrlsQuery } from './helpers/hooks';
|
import { useShortUrlsQuery } from './helpers/hooks';
|
||||||
import { SHORT_URLS_ORDERABLE_FIELDS, ShortUrlsOrder, ShortUrlsOrderableFields } from './data';
|
|
||||||
import { ExportShortUrlsBtnProps } from './helpers/ExportShortUrlsBtn';
|
|
||||||
import { TagsSelectorProps } from '../tags/helpers/TagsSelector';
|
|
||||||
import { ShortUrlsFilterDropdown } from './helpers/ShortUrlsFilterDropdown';
|
import { ShortUrlsFilterDropdown } from './helpers/ShortUrlsFilterDropdown';
|
||||||
import { Settings } from '../settings/reducers/settings';
|
|
||||||
import './ShortUrlsFilteringBar.scss';
|
import './ShortUrlsFilteringBar.scss';
|
||||||
|
|
||||||
interface ShortUrlsFilteringProps {
|
interface ShortUrlsFilteringProps {
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
import { pipe } from 'ramda';
|
import { pipe } from 'ramda';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Card } from 'reactstrap';
|
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { determineOrderDir, OrderDir } from '../utils/helpers/ordering';
|
import { Card } from 'reactstrap';
|
||||||
import { getServerId, SelectedServer } from '../servers/data';
|
import type { ShlinkShortUrlsListParams, ShlinkShortUrlsOrder } from '../api/types';
|
||||||
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
||||||
import { Topics } from '../mercure/helpers/Topics';
|
import { Topics } from '../mercure/helpers/Topics';
|
||||||
import { TableOrderIcon } from '../utils/table/TableOrderIcon';
|
import type { SelectedServer } from '../servers/data';
|
||||||
import { ShlinkShortUrlsListParams, ShlinkShortUrlsOrder } from '../api/types';
|
import { getServerId } from '../servers/data';
|
||||||
import { DEFAULT_SHORT_URLS_ORDERING, Settings } from '../settings/reducers/settings';
|
import type { Settings } from '../settings/reducers/settings';
|
||||||
import { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
|
import { DEFAULT_SHORT_URLS_ORDERING } from '../settings/reducers/settings';
|
||||||
import { ShortUrlsTableType } from './ShortUrlsTable';
|
|
||||||
import { Paginator } from './Paginator';
|
|
||||||
import { useShortUrlsQuery } from './helpers/hooks';
|
|
||||||
import { ShortUrlsOrder, ShortUrlsOrderableFields } from './data';
|
|
||||||
import { ShortUrlsFilteringBarType } from './ShortUrlsFilteringBar';
|
|
||||||
import { supportsExcludeBotsOnShortUrls } from '../utils/helpers/features';
|
import { supportsExcludeBotsOnShortUrls } from '../utils/helpers/features';
|
||||||
|
import type { OrderDir } from '../utils/helpers/ordering';
|
||||||
|
import { determineOrderDir } from '../utils/helpers/ordering';
|
||||||
|
import { TableOrderIcon } from '../utils/table/TableOrderIcon';
|
||||||
|
import type { ShortUrlsOrder, ShortUrlsOrderableFields } from './data';
|
||||||
|
import { useShortUrlsQuery } from './helpers/hooks';
|
||||||
|
import { Paginator } from './Paginator';
|
||||||
|
import type { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
|
||||||
|
import type { ShortUrlsFilteringBarType } from './ShortUrlsFilteringBar';
|
||||||
|
import type { ShortUrlsTableType } from './ShortUrlsTable';
|
||||||
|
|
||||||
interface ShortUrlsListProps {
|
interface ShortUrlsListProps {
|
||||||
selectedServer: SelectedServer;
|
selectedServer: SelectedServer;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { ReactNode } from 'react';
|
|
||||||
import { isEmpty } from 'ramda';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { SelectedServer } from '../servers/data';
|
import { isEmpty } from 'ramda';
|
||||||
import { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
|
import type { ReactNode } from 'react';
|
||||||
import { ShortUrlsRowType } from './helpers/ShortUrlsRow';
|
import type { SelectedServer } from '../servers/data';
|
||||||
import { ShortUrlsOrderableFields } from './data';
|
import type { ShortUrlsOrderableFields } from './data';
|
||||||
|
import type { ShortUrlsRowType } from './helpers/ShortUrlsRow';
|
||||||
|
import type { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
|
||||||
import './ShortUrlsTable.scss';
|
import './ShortUrlsTable.scss';
|
||||||
|
|
||||||
interface ShortUrlsTableProps {
|
interface ShortUrlsTableProps {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { Modal, ModalBody, ModalHeader } from 'reactstrap';
|
import { Modal, ModalBody, ModalHeader } from 'reactstrap';
|
||||||
import { useToggle } from '../utils/helpers/hooks';
|
import { useToggle } from '../utils/helpers/hooks';
|
||||||
import './UseExistingIfFoundInfoIcon.scss';
|
import './UseExistingIfFoundInfoIcon.scss';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Nullable, OptionalString } from '../../utils/utils';
|
import type { Order } from '../../utils/helpers/ordering';
|
||||||
import { Order } from '../../utils/helpers/ordering';
|
import type { Nullable, OptionalString } from '../../utils/utils';
|
||||||
|
|
||||||
export interface EditShortUrlData {
|
export interface EditShortUrlData {
|
||||||
longUrl?: string;
|
longUrl?: string;
|
||||||
|
|
|
@ -4,11 +4,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||||
import { Tooltip } from 'reactstrap';
|
import { Tooltip } from 'reactstrap';
|
||||||
import { ShortUrlCreation } from '../reducers/shortUrlCreation';
|
|
||||||
import { TimeoutToggle } from '../../utils/helpers/hooks';
|
|
||||||
import { Result } from '../../utils/Result';
|
|
||||||
import './CreateShortUrlResult.scss';
|
|
||||||
import { ShlinkApiError } from '../../api/ShlinkApiError';
|
import { ShlinkApiError } from '../../api/ShlinkApiError';
|
||||||
|
import type { TimeoutToggle } from '../../utils/helpers/hooks';
|
||||||
|
import { Result } from '../../utils/Result';
|
||||||
|
import type { ShortUrlCreation } from '../reducers/shortUrlCreation';
|
||||||
|
import './CreateShortUrlResult.scss';
|
||||||
|
|
||||||
export interface CreateShortUrlResultProps {
|
export interface CreateShortUrlResultProps {
|
||||||
creation: ShortUrlCreation;
|
creation: ShortUrlCreation;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
import { pipe } from 'ramda';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
|
||||||
import { pipe } from 'ramda';
|
|
||||||
import { ShortUrlDeletion } from '../reducers/shortUrlDeletion';
|
|
||||||
import { ShortUrlIdentifier, ShortUrlModalProps } from '../data';
|
|
||||||
import { handleEventPreventingDefault } from '../../utils/utils';
|
|
||||||
import { Result } from '../../utils/Result';
|
|
||||||
import { isInvalidDeletionError } from '../../api/utils';
|
|
||||||
import { ShlinkApiError } from '../../api/ShlinkApiError';
|
import { ShlinkApiError } from '../../api/ShlinkApiError';
|
||||||
|
import { isInvalidDeletionError } from '../../api/utils';
|
||||||
|
import { Result } from '../../utils/Result';
|
||||||
|
import { handleEventPreventingDefault } from '../../utils/utils';
|
||||||
|
import type { ShortUrlIdentifier, ShortUrlModalProps } from '../data';
|
||||||
|
import type { ShortUrlDeletion } from '../reducers/shortUrlDeletion';
|
||||||
|
|
||||||
interface DeleteShortUrlModalConnectProps extends ShortUrlModalProps {
|
interface DeleteShortUrlModalConnectProps extends ShortUrlModalProps {
|
||||||
shortUrlDeletion: ShortUrlDeletion;
|
shortUrlDeletion: ShortUrlDeletion;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import type { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
|
import type { ReportExporter } from '../../common/services/ReportExporter';
|
||||||
|
import type { SelectedServer } from '../../servers/data';
|
||||||
|
import { isServerWithId } from '../../servers/data';
|
||||||
import { ExportBtn } from '../../utils/ExportBtn';
|
import { ExportBtn } from '../../utils/ExportBtn';
|
||||||
import { useToggle } from '../../utils/helpers/hooks';
|
import { useToggle } from '../../utils/helpers/hooks';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import type { ShortUrl } from '../data';
|
||||||
import { isServerWithId, SelectedServer } from '../../servers/data';
|
|
||||||
import { ShortUrl } from '../data';
|
|
||||||
import { ReportExporter } from '../../common/services/ReportExporter';
|
|
||||||
import { useShortUrlsQuery } from './hooks';
|
import { useShortUrlsQuery } from './hooks';
|
||||||
|
|
||||||
export interface ExportShortUrlsBtnProps {
|
export interface ExportShortUrlsBtnProps {
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import { useMemo, useState } from 'react';
|
|
||||||
import { Modal, FormGroup, ModalBody, ModalHeader, Row, Button } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faFileDownload as downloadIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faFileDownload as downloadIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
import { ExternalLink } from 'react-external-link';
|
import { ExternalLink } from 'react-external-link';
|
||||||
import { ShortUrlModalProps } from '../data';
|
import { Button, FormGroup, Modal, ModalBody, ModalHeader, Row } from 'reactstrap';
|
||||||
import { SelectedServer } from '../../servers/data';
|
import type { ImageDownloader } from '../../common/services/ImageDownloader';
|
||||||
|
import type { SelectedServer } from '../../servers/data';
|
||||||
import { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon';
|
import { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon';
|
||||||
import { buildQrCodeUrl, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes';
|
|
||||||
import { supportsNonRestCors } from '../../utils/helpers/features';
|
import { supportsNonRestCors } from '../../utils/helpers/features';
|
||||||
import { ImageDownloader } from '../../common/services/ImageDownloader';
|
import type { QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes';
|
||||||
import { QrFormatDropdown } from './qr-codes/QrFormatDropdown';
|
import { buildQrCodeUrl } from '../../utils/helpers/qrCodes';
|
||||||
|
import type { ShortUrlModalProps } from '../data';
|
||||||
import { QrErrorCorrectionDropdown } from './qr-codes/QrErrorCorrectionDropdown';
|
import { QrErrorCorrectionDropdown } from './qr-codes/QrErrorCorrectionDropdown';
|
||||||
|
import { QrFormatDropdown } from './qr-codes/QrFormatDropdown';
|
||||||
import './QrCodeModal.scss';
|
import './QrCodeModal.scss';
|
||||||
|
|
||||||
interface QrCodeModalConnectProps extends ShortUrlModalProps {
|
interface QrCodeModalConnectProps extends ShortUrlModalProps {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { isServerWithId, SelectedServer, ServerWithId } from '../../servers/data';
|
import type { SelectedServer, ServerWithId } from '../../servers/data';
|
||||||
import { ShortUrl } from '../data';
|
import { isServerWithId } from '../../servers/data';
|
||||||
|
import type { ShortUrl } from '../data';
|
||||||
import { urlEncodeShortCode } from './index';
|
import { urlEncodeShortCode } from './index';
|
||||||
|
|
||||||
export type LinkSuffix = 'visits' | 'edit';
|
export type LinkSuffix = 'visits' | 'edit';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChangeEvent, FC, PropsWithChildren } from 'react';
|
import type { ChangeEvent, FC, PropsWithChildren } from 'react';
|
||||||
import { Checkbox } from '../../utils/Checkbox';
|
import { Checkbox } from '../../utils/Checkbox';
|
||||||
import { InfoTooltip } from '../../utils/InfoTooltip';
|
import { InfoTooltip } from '../../utils/InfoTooltip';
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue