From 6094994cfae13dedc43afb126c44f16fc31f7fab Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 14 Nov 2025 23:29:59 +0100 Subject: [PATCH] Do not inject settings state or actions --- src/api/services/ShlinkApiClientBuilder.ts | 5 ++--- src/app/App.tsx | 6 +++--- src/app/services/provideServices.ts | 2 +- src/common/ShlinkWebComponentContainer.tsx | 11 ++++------- src/common/services/provideServices.ts | 11 +---------- src/container/index.ts | 2 +- src/index.tsx | 4 +++- test/app/App.test.tsx | 3 ++- test/common/ShlinkWebComponentContainer.test.tsx | 4 ++-- 9 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/api/services/ShlinkApiClientBuilder.ts b/src/api/services/ShlinkApiClientBuilder.ts index b6216a16..caf269f8 100644 --- a/src/api/services/ShlinkApiClientBuilder.ts +++ b/src/api/services/ShlinkApiClientBuilder.ts @@ -6,8 +6,6 @@ import type { GetState } from '../../store'; const apiClients: Map = new Map(); -const isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState => - typeof getStateOrSelectedServer === 'function'; const getSelectedServerFromState = (getState: GetState): ServerWithId => { const { selectedServer } = getState(); if (!hasServerData(selectedServer)) { @@ -18,7 +16,7 @@ const getSelectedServerFromState = (getState: 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) : getStateOrSelectedServer; const serverKey = `${apiKey}_${baseUrl}_${forwardCredentials ? 'forward' : 'no-forward'}`; @@ -34,6 +32,7 @@ export const buildShlinkApiClient = (httpClient: HttpClient) => (getStateOrSelec { requestCredentials: forwardCredentials ? 'include' : undefined }, ); apiClients.set(serverKey, apiClient); + return apiClient; }; diff --git a/src/app/App.tsx b/src/app/App.tsx index 02bda524..ede79ee6 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,6 +1,5 @@ import { changeThemeInMarkup, getSystemPreferredTheme } from '@shlinkio/shlink-frontend-kit'; import type { HttpClient } from '@shlinkio/shlink-js-sdk'; -import type { Settings as AppSettings } from '@shlinkio/shlink-web-component/settings'; import { clsx } from 'clsx'; import type { FC } from 'react'; import { useEffect } from 'react'; @@ -13,11 +12,11 @@ import type { FCWithDeps } from '../container/utils'; import { componentFactory, useDependencies } from '../container/utils'; import { EditServer } from '../servers/EditServer'; import { useLoadRemoteServers } from '../servers/reducers/remoteServers'; +import { useSettings } from '../settings/reducers/settings'; import { Settings } from '../settings/Settings'; import { forceUpdate } from '../utils/helpers/sw'; export type AppProps = { - settings: AppSettings; resetAppUpdate: () => void; appUpdated: boolean; }; @@ -30,7 +29,7 @@ type AppDeps = { HttpClient: HttpClient; }; -const App: FCWithDeps = ({ settings, appUpdated, resetAppUpdate }) => { +const App: FCWithDeps = ({ appUpdated, resetAppUpdate }) => { const { Home, ShlinkWebComponentContainer, @@ -44,6 +43,7 @@ const App: FCWithDeps = ({ settings, appUpdated, resetAppUpda const location = useLocation(); const isHome = location.pathname === '/'; + const { settings } = useSettings(); useEffect(() => { changeThemeInMarkup(settings.ui?.theme ?? getSystemPreferredTheme()); }, [settings.ui?.theme]); diff --git a/src/app/services/provideServices.ts b/src/app/services/provideServices.ts index 9314dca1..80278b93 100644 --- a/src/app/services/provideServices.ts +++ b/src/app/services/provideServices.ts @@ -6,7 +6,7 @@ import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates'; export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Components bottle.factory('App', AppFactory); - bottle.decorator('App', connect(['settings', 'appUpdated'], ['resetAppUpdate'])); + bottle.decorator('App', connect(['appUpdated'], ['resetAppUpdate'])); // Actions bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable); diff --git a/src/common/ShlinkWebComponentContainer.tsx b/src/common/ShlinkWebComponentContainer.tsx index ff76df25..4db6ab9a 100644 --- a/src/common/ShlinkWebComponentContainer.tsx +++ b/src/common/ShlinkWebComponentContainer.tsx @@ -4,7 +4,6 @@ import { ShlinkSidebarVisibilityProvider, ShlinkWebComponent, } from '@shlinkio/shlink-web-component'; -import type { Settings } from '@shlinkio/shlink-web-component/settings'; import { memo } from 'react'; import type { FCWithDeps } 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 { withSelectedServer } from '../servers/helpers/withSelectedServer'; import { useSelectedServer } from '../servers/reducers/selectedServer'; +import { useSettings } from '../settings/reducers/settings'; import { NotFound } from './NotFound'; -type ShlinkWebComponentContainerProps = { - settings: Settings; -}; - type ShlinkWebComponentContainerDeps = WithSelectedServerPropsDeps & { TagColorsStorage: TagColorsStorage, }; const ShlinkWebComponentContainer: FCWithDeps< - ShlinkWebComponentContainerProps, + any, ShlinkWebComponentContainerDeps // 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 // extra rendering there. // This should be revisited at some point. -> = withSelectedServer(memo(({ settings }) => { +> = withSelectedServer(memo(() => { const { buildShlinkApiClient, TagColorsStorage: tagColorsStorage, } = useDependencies(ShlinkWebComponentContainer); const { selectedServer } = useSelectedServer(); + const { settings } = useSettings(); if (!isReachableServer(selectedServer)) { return ; diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index 20026d69..001bbe08 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -1,27 +1,18 @@ import { FetchHttpClient } from '@shlinkio/shlink-js-sdk/fetch'; import type Bottle from 'bottlejs'; -import type { ConnectDecorator } from '../../container/types'; import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer'; -import { ErrorHandler } from '../ErrorHandler'; import { Home } from '../Home'; -import { ScrollToTop } from '../ScrollToTop'; import { ShlinkWebComponentContainerFactory } from '../ShlinkWebComponentContainer'; -export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { +export const provideServices = (bottle: Bottle) => { // Services bottle.constant('window', window); bottle.constant('console', console); bottle.constant('fetch', window.fetch.bind(window)); bottle.service('HttpClient', FetchHttpClient, 'fetch'); - // Components - bottle.serviceFactory('ScrollToTop', () => ScrollToTop); - bottle.serviceFactory('Home', () => Home); bottle.decorator('Home', withoutSelectedServer); bottle.factory('ShlinkWebComponentContainer', ShlinkWebComponentContainerFactory); - bottle.decorator('ShlinkWebComponentContainer', connect(['settings'], [])); - - bottle.serviceFactory('ErrorHandler', () => ErrorHandler); }; diff --git a/src/container/index.ts b/src/container/index.ts index 604f04fd..d7fa9606 100644 --- a/src/container/index.ts +++ b/src/container/index.ts @@ -34,7 +34,7 @@ const connect: ConnectDecorator = (propsFromState: string[] | null, actionServic ); provideAppServices(bottle, connect); -provideCommonServices(bottle, connect); +provideCommonServices(bottle); provideApiServices(bottle); provideServersServices(bottle); provideUtilsServices(bottle); diff --git a/src/index.tsx b/src/index.tsx index 4dd136b4..7829245d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,13 +2,15 @@ import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router'; import pack from '../package.json'; +import { ErrorHandler } from './common/ErrorHandler'; +import { ScrollToTop } from './common/ScrollToTop'; import { container } from './container'; import { register as registerServiceWorker } from './serviceWorkerRegistration'; import { setUpStore } from './store'; import './tailwind.css'; const store = setUpStore(); -const { App, ScrollToTop, ErrorHandler, appUpdateAvailable } = container; +const { App, appUpdateAvailable } = container; createRoot(document.getElementById('root')!).render( diff --git a/test/app/App.test.tsx b/test/app/App.test.tsx index 200f131d..ed6cf6e6 100644 --- a/test/app/App.test.tsx +++ b/test/app/App.test.tsx @@ -19,7 +19,7 @@ describe('', () => { ); const setUp = async (activeRoute = '/') => act(() => renderWithStore( - {}} /> + {}} /> , { initialState: { @@ -27,6 +27,7 @@ describe('', () => { abc123: fromPartial({ id: 'abc123', name: 'abc123 server' }), def456: fromPartial({ id: 'def456', name: 'def456 server' }), }, + settings: fromPartial({}), }, }, )); diff --git a/test/common/ShlinkWebComponentContainer.test.tsx b/test/common/ShlinkWebComponentContainer.test.tsx index 12d429bb..361fa980 100644 --- a/test/common/ShlinkWebComponentContainer.test.tsx +++ b/test/common/ShlinkWebComponentContainer.test.tsx @@ -19,10 +19,10 @@ describe('', () => { })); const setUp = (selectedServer: SelectedServer) => renderWithStore( - + , { - initialState: { selectedServer, servers: {} }, + initialState: { selectedServer, servers: {}, settings: {} }, }, );