mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Merge pull request #785 from acelaya-forks/feature/server-error-fix
Feature/server error fix
This commit is contained in:
commit
7f6c678eaa
9 changed files with 32 additions and 20 deletions
|
@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).
|
||||||
|
|
||||||
## [Unreleased]
|
## [3.9.0] - 2022-12-31
|
||||||
### Added
|
### Added
|
||||||
* [#750](https://github.com/shlinkio/shlink-web-client/issues/750) Added new icon indicators telling if a short URL can be normally visited, it received the max amount of visits, is still not enabled, etc.
|
* [#750](https://github.com/shlinkio/shlink-web-client/issues/750) Added new icon indicators telling if a short URL can be normally visited, it received the max amount of visits, is still not enabled, etc.
|
||||||
* [#764](https://github.com/shlinkio/shlink-web-client/issues/764) Added support to exclude visits from visits on short URLs list when consuming Shlink 3.4.0.
|
* [#764](https://github.com/shlinkio/shlink-web-client/issues/764) Added support to exclude visits from visits on short URLs list when consuming Shlink 3.4.0.
|
||||||
|
@ -26,7 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
* [#774](https://github.com/shlinkio/shlink-web-client/issues/774) Dropped support for Shlink older than 2.8.0.
|
* [#774](https://github.com/shlinkio/shlink-web-client/issues/774) Dropped support for Shlink older than 2.8.0.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* *Nothing*
|
* [#715](https://github.com/shlinkio/shlink-web-client/issues/715) Fixed connection still failing on miss-configured servers, after editing their params to set proper values.
|
||||||
|
|
||||||
|
|
||||||
## [3.8.2] - 2022-12-17
|
## [3.8.2] - 2022-12-17
|
||||||
|
|
|
@ -38,7 +38,6 @@ export const MenuLayout = (
|
||||||
useEffect(() => hideSidebar(), [location]);
|
useEffect(() => hideSidebar(), [location]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
showContent && sidebarPresent();
|
showContent && sidebarPresent();
|
||||||
|
|
||||||
return () => sidebarNotPresent();
|
return () => sidebarNotPresent();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Button } from 'reactstrap';
|
import { Button } from 'reactstrap';
|
||||||
import { NoMenuLayout } from '../common/NoMenuLayout';
|
import { NoMenuLayout } from '../common/NoMenuLayout';
|
||||||
import { useGoBack } from '../utils/helpers/hooks';
|
import { useGoBack, useParsedQuery } from '../utils/helpers/hooks';
|
||||||
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';
|
import { isServerWithId, ServerData } from './data';
|
||||||
|
@ -10,8 +10,11 @@ interface EditServerProps {
|
||||||
editServer: (serverId: string, serverData: ServerData) => void;
|
editServer: (serverId: string, serverData: ServerData) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditServer = (ServerError: FC) => withSelectedServer<EditServerProps>(({ editServer, selectedServer }) => {
|
export const EditServer = (ServerError: FC) => withSelectedServer<EditServerProps>((
|
||||||
|
{ editServer, selectedServer, selectServer },
|
||||||
|
) => {
|
||||||
const goBack = useGoBack();
|
const goBack = useGoBack();
|
||||||
|
const { reconnect } = useParsedQuery<{ reconnect?: 'true' }>();
|
||||||
|
|
||||||
if (!isServerWithId(selectedServer)) {
|
if (!isServerWithId(selectedServer)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -19,6 +22,7 @@ export const EditServer = (ServerError: FC) => withSelectedServer<EditServerProp
|
||||||
|
|
||||||
const handleSubmit = (serverData: ServerData) => {
|
const handleSubmit = (serverData: ServerData) => {
|
||||||
editServer(selectedServer.id, serverData);
|
editServer(selectedServer.id, serverData);
|
||||||
|
reconnect === 'true' && selectServer(selectedServer.id);
|
||||||
goBack();
|
goBack();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ export const ServerError = (DeleteServerButton: FC<DeleteServerButtonProps>): FC
|
||||||
<h5>
|
<h5>
|
||||||
Alternatively, if you think you may have miss-configured this server, you
|
Alternatively, if you think you may have miss-configured this server, you
|
||||||
can <DeleteServerButton server={selectedServer} className="server-error__delete-btn">remove it</DeleteServerButton> or
|
can <DeleteServerButton server={selectedServer} className="server-error__delete-btn">remove it</DeleteServerButton> or
|
||||||
<Link to={`/server/${selectedServer.id}/edit`}>edit it</Link>.
|
<Link to={`/server/${selectedServer.id}/edit?reconnect=true`}>edit it</Link>.
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createAction, createListenerMiddleware, createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createAction, createListenerMiddleware, createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { identity, memoizeWith, pipe } from 'ramda';
|
import { memoizeWith, pipe } from 'ramda';
|
||||||
import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';
|
import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';
|
||||||
import { isReachableServer, SelectedServer } from '../data';
|
import { isReachableServer, SelectedServer, ServerWithId } from '../data';
|
||||||
import { 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 { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
|
@ -18,8 +18,8 @@ const versionToSemVer = pipe(
|
||||||
);
|
);
|
||||||
|
|
||||||
const getServerVersion = memoizeWith(
|
const getServerVersion = memoizeWith(
|
||||||
identity,
|
(server: ServerWithId) => `${server.id}_${server.url}_${server.apiKey}`,
|
||||||
async (_serverId: string, health: () => Promise<ShlinkHealth>) => health().then(({ version }) => ({
|
async (_server: ServerWithId, health: () => Promise<ShlinkHealth>) => health().then(({ version }) => ({
|
||||||
version: versionToSemVer(version),
|
version: versionToSemVer(version),
|
||||||
printableVersion: versionToPrintable(version),
|
printableVersion: versionToPrintable(version),
|
||||||
})),
|
})),
|
||||||
|
@ -43,7 +43,7 @@ export const selectServer = (buildShlinkApiClient: ShlinkApiClientBuilder) => cr
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { health } = buildShlinkApiClient(selectedServer);
|
const { health } = buildShlinkApiClient(selectedServer);
|
||||||
const { version, printableVersion } = await getServerVersion(serverId, health);
|
const { version, printableVersion } = await getServerVersion(selectedServer, health);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...selectedServer,
|
...selectedServer,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState, useRef, EffectCallback, DependencyList, useEffect } from 'react';
|
import { useState, useRef, EffectCallback, DependencyList, useEffect } from 'react';
|
||||||
import { useSwipeable as useReactSwipeable } from 'react-swipeable';
|
import { useSwipeable as useReactSwipeable } from 'react-swipeable';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { parseQuery, stringifyQuery } from './query';
|
import { parseQuery, stringifyQuery } from './query';
|
||||||
|
|
||||||
|
@ -82,6 +82,11 @@ export const useGoBack = () => {
|
||||||
return () => navigate(-1);
|
return () => navigate(-1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useParsedQuery = <T>(): T => {
|
||||||
|
const { search } = useLocation();
|
||||||
|
return parseQuery<T>(search);
|
||||||
|
};
|
||||||
|
|
||||||
export const useDomId = (): string => {
|
export const useDomId = (): string => {
|
||||||
const { current: id } = useRef(`dom-${uuid()}`);
|
const { current: id } = useRef(`dom-${uuid()}`);
|
||||||
return id;
|
return id;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { fireEvent, screen } from '@testing-library/react';
|
import { fireEvent, screen } from '@testing-library/react';
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { MemoryRouter, useNavigate } from 'react-router-dom';
|
||||||
import { EditServer as editServerConstruct } from '../../src/servers/EditServer';
|
import { EditServer as editServerConstruct } from '../../src/servers/EditServer';
|
||||||
import { ReachableServer, SelectedServer } from '../../src/servers/data';
|
import { ReachableServer, SelectedServer } from '../../src/servers/data';
|
||||||
import { renderWithEvents } from '../__helpers__/setUpTest';
|
import { renderWithEvents } from '../__helpers__/setUpTest';
|
||||||
|
@ -19,7 +19,9 @@ describe('<EditServer />', () => {
|
||||||
});
|
});
|
||||||
const EditServer = editServerConstruct(ServerError);
|
const EditServer = editServerConstruct(ServerError);
|
||||||
const setUp = (selectedServer: SelectedServer = defaultSelectedServer) => renderWithEvents(
|
const setUp = (selectedServer: SelectedServer = defaultSelectedServer) => renderWithEvents(
|
||||||
<EditServer editServer={editServerMock} selectedServer={selectedServer} selectServer={jest.fn()} />,
|
<MemoryRouter>
|
||||||
|
<EditServer editServer={editServerMock} selectedServer={selectedServer} selectServer={jest.fn()} />
|
||||||
|
</MemoryRouter>,
|
||||||
);
|
);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
|
@ -39,11 +39,12 @@ describe('selectedServerReducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('selectServer', () => {
|
describe('selectServer', () => {
|
||||||
const selectedServer = {
|
|
||||||
id: 'abc123',
|
|
||||||
};
|
|
||||||
const version = '1.19.0';
|
const version = '1.19.0';
|
||||||
const createGetStateMock = (id: string) => jest.fn().mockReturnValue({ servers: { [id]: selectedServer } });
|
const createGetStateMock = (id: string) => jest.fn().mockReturnValue({
|
||||||
|
servers: {
|
||||||
|
[id]: { id },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[version, version, `v${version}`],
|
[version, version, `v${version}`],
|
||||||
|
@ -53,7 +54,7 @@ describe('selectedServerReducer', () => {
|
||||||
const id = uuid();
|
const id = uuid();
|
||||||
const getState = createGetStateMock(id);
|
const getState = createGetStateMock(id);
|
||||||
const expectedSelectedServer = {
|
const expectedSelectedServer = {
|
||||||
...selectedServer,
|
id,
|
||||||
version: expectedVersion,
|
version: expectedVersion,
|
||||||
printableVersion: expectedPrintableVersion,
|
printableVersion: expectedPrintableVersion,
|
||||||
};
|
};
|
||||||
|
@ -84,7 +85,7 @@ describe('selectedServerReducer', () => {
|
||||||
it('dispatches error when health endpoint fails', async () => {
|
it('dispatches error when health endpoint fails', async () => {
|
||||||
const id = uuid();
|
const id = uuid();
|
||||||
const getState = createGetStateMock(id);
|
const getState = createGetStateMock(id);
|
||||||
const expectedSelectedServer = Mock.of<NonReachableServer>({ ...selectedServer, serverNotReachable: true });
|
const expectedSelectedServer = Mock.of<NonReachableServer>({ id, serverNotReachable: true });
|
||||||
|
|
||||||
health.mockRejectedValue({});
|
health.mockRejectedValue({});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import pack from './package.json';
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react(), VitePWA({
|
plugins: [react(), VitePWA({
|
||||||
|
mode: process.env.NODE_ENV === 'development' ? 'development' : 'production',
|
||||||
strategies: 'injectManifest',
|
strategies: 'injectManifest',
|
||||||
srcDir: './src',
|
srcDir: './src',
|
||||||
filename: 'service-worker.ts',
|
filename: 'service-worker.ts',
|
||||||
|
|
Loading…
Reference in a new issue