mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-15 03:53:51 +00:00
Do not inject settings state or actions
This commit is contained in:
@@ -6,8 +6,6 @@ import type { GetState } from '../../store';
|
|||||||
|
|
||||||
const apiClients: Map<string, ShlinkApiClient> = new Map();
|
const apiClients: Map<string, ShlinkApiClient> = new Map();
|
||||||
|
|
||||||
const isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState =>
|
|
||||||
typeof getStateOrSelectedServer === 'function';
|
|
||||||
const getSelectedServerFromState = (getState: GetState): ServerWithId => {
|
const getSelectedServerFromState = (getState: GetState): ServerWithId => {
|
||||||
const { selectedServer } = getState();
|
const { selectedServer } = getState();
|
||||||
if (!hasServerData(selectedServer)) {
|
if (!hasServerData(selectedServer)) {
|
||||||
@@ -18,7 +16,7 @@ const getSelectedServerFromState = (getState: GetState): ServerWithId => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const buildShlinkApiClient = (httpClient: HttpClient) => (getStateOrSelectedServer: GetState | ServerWithId) => {
|
export const buildShlinkApiClient = (httpClient: HttpClient) => (getStateOrSelectedServer: GetState | ServerWithId) => {
|
||||||
const { url: baseUrl, apiKey, forwardCredentials } = isGetState(getStateOrSelectedServer)
|
const { url: baseUrl, apiKey, forwardCredentials } = typeof getStateOrSelectedServer === 'function'
|
||||||
? getSelectedServerFromState(getStateOrSelectedServer)
|
? getSelectedServerFromState(getStateOrSelectedServer)
|
||||||
: getStateOrSelectedServer;
|
: getStateOrSelectedServer;
|
||||||
const serverKey = `${apiKey}_${baseUrl}_${forwardCredentials ? 'forward' : 'no-forward'}`;
|
const serverKey = `${apiKey}_${baseUrl}_${forwardCredentials ? 'forward' : 'no-forward'}`;
|
||||||
@@ -34,6 +32,7 @@ export const buildShlinkApiClient = (httpClient: HttpClient) => (getStateOrSelec
|
|||||||
{ requestCredentials: forwardCredentials ? 'include' : undefined },
|
{ requestCredentials: forwardCredentials ? 'include' : undefined },
|
||||||
);
|
);
|
||||||
apiClients.set(serverKey, apiClient);
|
apiClients.set(serverKey, apiClient);
|
||||||
|
|
||||||
return apiClient;
|
return apiClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { changeThemeInMarkup, getSystemPreferredTheme } from '@shlinkio/shlink-frontend-kit';
|
import { changeThemeInMarkup, getSystemPreferredTheme } from '@shlinkio/shlink-frontend-kit';
|
||||||
import type { HttpClient } from '@shlinkio/shlink-js-sdk';
|
import type { HttpClient } from '@shlinkio/shlink-js-sdk';
|
||||||
import type { Settings as AppSettings } from '@shlinkio/shlink-web-component/settings';
|
|
||||||
import { clsx } from 'clsx';
|
import { clsx } from 'clsx';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
@@ -13,11 +12,11 @@ import type { FCWithDeps } from '../container/utils';
|
|||||||
import { componentFactory, useDependencies } from '../container/utils';
|
import { componentFactory, useDependencies } from '../container/utils';
|
||||||
import { EditServer } from '../servers/EditServer';
|
import { EditServer } from '../servers/EditServer';
|
||||||
import { useLoadRemoteServers } from '../servers/reducers/remoteServers';
|
import { useLoadRemoteServers } from '../servers/reducers/remoteServers';
|
||||||
|
import { useSettings } from '../settings/reducers/settings';
|
||||||
import { Settings } from '../settings/Settings';
|
import { Settings } from '../settings/Settings';
|
||||||
import { forceUpdate } from '../utils/helpers/sw';
|
import { forceUpdate } from '../utils/helpers/sw';
|
||||||
|
|
||||||
export type AppProps = {
|
export type AppProps = {
|
||||||
settings: AppSettings;
|
|
||||||
resetAppUpdate: () => void;
|
resetAppUpdate: () => void;
|
||||||
appUpdated: boolean;
|
appUpdated: boolean;
|
||||||
};
|
};
|
||||||
@@ -30,7 +29,7 @@ type AppDeps = {
|
|||||||
HttpClient: HttpClient;
|
HttpClient: HttpClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
const App: FCWithDeps<AppProps, AppDeps> = ({ settings, appUpdated, resetAppUpdate }) => {
|
const App: FCWithDeps<AppProps, AppDeps> = ({ appUpdated, resetAppUpdate }) => {
|
||||||
const {
|
const {
|
||||||
Home,
|
Home,
|
||||||
ShlinkWebComponentContainer,
|
ShlinkWebComponentContainer,
|
||||||
@@ -44,6 +43,7 @@ const App: FCWithDeps<AppProps, AppDeps> = ({ settings, appUpdated, resetAppUpda
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const isHome = location.pathname === '/';
|
const isHome = location.pathname === '/';
|
||||||
|
|
||||||
|
const { settings } = useSettings();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changeThemeInMarkup(settings.ui?.theme ?? getSystemPreferredTheme());
|
changeThemeInMarkup(settings.ui?.theme ?? getSystemPreferredTheme());
|
||||||
}, [settings.ui?.theme]);
|
}, [settings.ui?.theme]);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';
|
|||||||
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
// Components
|
// Components
|
||||||
bottle.factory('App', AppFactory);
|
bottle.factory('App', AppFactory);
|
||||||
bottle.decorator('App', connect(['settings', 'appUpdated'], ['resetAppUpdate']));
|
bottle.decorator('App', connect(['appUpdated'], ['resetAppUpdate']));
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);
|
bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
ShlinkSidebarVisibilityProvider,
|
ShlinkSidebarVisibilityProvider,
|
||||||
ShlinkWebComponent,
|
ShlinkWebComponent,
|
||||||
} from '@shlinkio/shlink-web-component';
|
} from '@shlinkio/shlink-web-component';
|
||||||
import type { Settings } from '@shlinkio/shlink-web-component/settings';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import type { FCWithDeps } from '../container/utils';
|
import type { FCWithDeps } from '../container/utils';
|
||||||
import { componentFactory, useDependencies } from '../container/utils';
|
import { componentFactory, useDependencies } from '../container/utils';
|
||||||
@@ -13,29 +12,27 @@ import { ServerError } from '../servers/helpers/ServerError';
|
|||||||
import type { WithSelectedServerPropsDeps } from '../servers/helpers/withSelectedServer';
|
import type { WithSelectedServerPropsDeps } from '../servers/helpers/withSelectedServer';
|
||||||
import { withSelectedServer } from '../servers/helpers/withSelectedServer';
|
import { withSelectedServer } from '../servers/helpers/withSelectedServer';
|
||||||
import { useSelectedServer } from '../servers/reducers/selectedServer';
|
import { useSelectedServer } from '../servers/reducers/selectedServer';
|
||||||
|
import { useSettings } from '../settings/reducers/settings';
|
||||||
import { NotFound } from './NotFound';
|
import { NotFound } from './NotFound';
|
||||||
|
|
||||||
type ShlinkWebComponentContainerProps = {
|
|
||||||
settings: Settings;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ShlinkWebComponentContainerDeps = WithSelectedServerPropsDeps & {
|
type ShlinkWebComponentContainerDeps = WithSelectedServerPropsDeps & {
|
||||||
TagColorsStorage: TagColorsStorage,
|
TagColorsStorage: TagColorsStorage,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ShlinkWebComponentContainer: FCWithDeps<
|
const ShlinkWebComponentContainer: FCWithDeps<
|
||||||
ShlinkWebComponentContainerProps,
|
any,
|
||||||
ShlinkWebComponentContainerDeps
|
ShlinkWebComponentContainerDeps
|
||||||
// FIXME Using `memo` here to solve a flickering effect in charts.
|
// FIXME Using `memo` here to solve a flickering effect in charts.
|
||||||
// memo is probably not the right solution. The root cause is the withSelectedServer HOC, but I couldn't fix the
|
// memo is probably not the right solution. The root cause is the withSelectedServer HOC, but I couldn't fix the
|
||||||
// extra rendering there.
|
// extra rendering there.
|
||||||
// This should be revisited at some point.
|
// This should be revisited at some point.
|
||||||
> = withSelectedServer(memo(({ settings }) => {
|
> = withSelectedServer(memo(() => {
|
||||||
const {
|
const {
|
||||||
buildShlinkApiClient,
|
buildShlinkApiClient,
|
||||||
TagColorsStorage: tagColorsStorage,
|
TagColorsStorage: tagColorsStorage,
|
||||||
} = useDependencies(ShlinkWebComponentContainer);
|
} = useDependencies(ShlinkWebComponentContainer);
|
||||||
const { selectedServer } = useSelectedServer();
|
const { selectedServer } = useSelectedServer();
|
||||||
|
const { settings } = useSettings();
|
||||||
|
|
||||||
if (!isReachableServer(selectedServer)) {
|
if (!isReachableServer(selectedServer)) {
|
||||||
return <ServerError />;
|
return <ServerError />;
|
||||||
|
|||||||
@@ -1,27 +1,18 @@
|
|||||||
import { FetchHttpClient } from '@shlinkio/shlink-js-sdk/fetch';
|
import { FetchHttpClient } from '@shlinkio/shlink-js-sdk/fetch';
|
||||||
import type Bottle from 'bottlejs';
|
import type Bottle from 'bottlejs';
|
||||||
import type { ConnectDecorator } from '../../container/types';
|
|
||||||
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
|
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
|
||||||
import { ErrorHandler } from '../ErrorHandler';
|
|
||||||
import { Home } from '../Home';
|
import { Home } from '../Home';
|
||||||
import { ScrollToTop } from '../ScrollToTop';
|
|
||||||
import { ShlinkWebComponentContainerFactory } from '../ShlinkWebComponentContainer';
|
import { ShlinkWebComponentContainerFactory } from '../ShlinkWebComponentContainer';
|
||||||
|
|
||||||
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle) => {
|
||||||
// Services
|
// Services
|
||||||
bottle.constant('window', window);
|
bottle.constant('window', window);
|
||||||
bottle.constant('console', console);
|
bottle.constant('console', console);
|
||||||
bottle.constant('fetch', window.fetch.bind(window));
|
bottle.constant('fetch', window.fetch.bind(window));
|
||||||
bottle.service('HttpClient', FetchHttpClient, 'fetch');
|
bottle.service('HttpClient', FetchHttpClient, 'fetch');
|
||||||
|
|
||||||
// Components
|
|
||||||
bottle.serviceFactory('ScrollToTop', () => ScrollToTop);
|
|
||||||
|
|
||||||
bottle.serviceFactory('Home', () => Home);
|
bottle.serviceFactory('Home', () => Home);
|
||||||
bottle.decorator('Home', withoutSelectedServer);
|
bottle.decorator('Home', withoutSelectedServer);
|
||||||
|
|
||||||
bottle.factory('ShlinkWebComponentContainer', ShlinkWebComponentContainerFactory);
|
bottle.factory('ShlinkWebComponentContainer', ShlinkWebComponentContainerFactory);
|
||||||
bottle.decorator('ShlinkWebComponentContainer', connect(['settings'], []));
|
|
||||||
|
|
||||||
bottle.serviceFactory('ErrorHandler', () => ErrorHandler);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const connect: ConnectDecorator = (propsFromState: string[] | null, actionServic
|
|||||||
);
|
);
|
||||||
|
|
||||||
provideAppServices(bottle, connect);
|
provideAppServices(bottle, connect);
|
||||||
provideCommonServices(bottle, connect);
|
provideCommonServices(bottle);
|
||||||
provideApiServices(bottle);
|
provideApiServices(bottle);
|
||||||
provideServersServices(bottle);
|
provideServersServices(bottle);
|
||||||
provideUtilsServices(bottle);
|
provideUtilsServices(bottle);
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ import { createRoot } from 'react-dom/client';
|
|||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { BrowserRouter } from 'react-router';
|
import { BrowserRouter } from 'react-router';
|
||||||
import pack from '../package.json';
|
import pack from '../package.json';
|
||||||
|
import { ErrorHandler } from './common/ErrorHandler';
|
||||||
|
import { ScrollToTop } from './common/ScrollToTop';
|
||||||
import { container } from './container';
|
import { container } from './container';
|
||||||
import { register as registerServiceWorker } from './serviceWorkerRegistration';
|
import { register as registerServiceWorker } from './serviceWorkerRegistration';
|
||||||
import { setUpStore } from './store';
|
import { setUpStore } from './store';
|
||||||
import './tailwind.css';
|
import './tailwind.css';
|
||||||
|
|
||||||
const store = setUpStore();
|
const store = setUpStore();
|
||||||
const { App, ScrollToTop, ErrorHandler, appUpdateAvailable } = container;
|
const { App, appUpdateAvailable } = container;
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ describe('<App />', () => {
|
|||||||
);
|
);
|
||||||
const setUp = async (activeRoute = '/') => act(() => renderWithStore(
|
const setUp = async (activeRoute = '/') => act(() => renderWithStore(
|
||||||
<MemoryRouter initialEntries={[{ pathname: activeRoute }]}>
|
<MemoryRouter initialEntries={[{ pathname: activeRoute }]}>
|
||||||
<App settings={fromPartial({})} appUpdated={false} resetAppUpdate={() => {}} />
|
<App appUpdated={false} resetAppUpdate={() => {}} />
|
||||||
</MemoryRouter>,
|
</MemoryRouter>,
|
||||||
{
|
{
|
||||||
initialState: {
|
initialState: {
|
||||||
@@ -27,6 +27,7 @@ describe('<App />', () => {
|
|||||||
abc123: fromPartial<ServerWithId>({ id: 'abc123', name: 'abc123 server' }),
|
abc123: fromPartial<ServerWithId>({ id: 'abc123', name: 'abc123 server' }),
|
||||||
def456: fromPartial<ServerWithId>({ id: 'def456', name: 'def456 server' }),
|
def456: fromPartial<ServerWithId>({ id: 'def456', name: 'def456 server' }),
|
||||||
},
|
},
|
||||||
|
settings: fromPartial({}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ describe('<ShlinkWebComponentContainer />', () => {
|
|||||||
}));
|
}));
|
||||||
const setUp = (selectedServer: SelectedServer) => renderWithStore(
|
const setUp = (selectedServer: SelectedServer) => renderWithStore(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<ShlinkWebComponentContainer settings={{}} />
|
<ShlinkWebComponentContainer />
|
||||||
</MemoryRouter>,
|
</MemoryRouter>,
|
||||||
{
|
{
|
||||||
initialState: { selectedServer, servers: {} },
|
initialState: { selectedServer, servers: {}, settings: {} },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user