From f7adcb8533fb71826953b7cc9d9ecfdac5d5d47e Mon Sep 17 00:00:00 2001 From: jeffvli Date: Mon, 15 Jun 2026 20:49:17 -0700 Subject: [PATCH] more potential fixes for server lock duplication --- .../action-required/utils/server-lock.ts | 34 ++++++++++++++++++ .../features/login/routes/login-route.tsx | 35 +++++++++++++------ src/renderer/router/app-outlet.tsx | 17 ++++----- 3 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 src/renderer/features/action-required/utils/server-lock.ts diff --git a/src/renderer/features/action-required/utils/server-lock.ts b/src/renderer/features/action-required/utils/server-lock.ts new file mode 100644 index 000000000..294da9191 --- /dev/null +++ b/src/renderer/features/action-required/utils/server-lock.ts @@ -0,0 +1,34 @@ +import { ServerListItemWithCredential } from '/@/shared/types/domain-types'; +import { ServerType } from '/@/shared/types/types'; + +export const normalizeServerUrl = (url: string) => url.replace(/\/$/, ''); + +export const findExistingServerLockServer = ( + serverList: Record, + configuredUrl: string, + serverType?: null | ServerType, +): ServerListItemWithCredential | undefined => { + const servers = Object.values(serverList); + + if (servers.length === 0) { + return undefined; + } + + const normalizedUrl = normalizeServerUrl(configuredUrl); + const byUrl = servers.find((server) => normalizeServerUrl(server.url) === normalizedUrl); + + if (byUrl) { + return byUrl; + } + + // Server lock allows only one server — reuse the existing entry even if the URL changed. + if (servers.length === 1) { + return servers[0]; + } + + if (serverType) { + return servers.find((server) => server.type === serverType); + } + + return undefined; +}; diff --git a/src/renderer/features/login/routes/login-route.tsx b/src/renderer/features/login/routes/login-route.tsx index a3833df53..468b8a7c6 100644 --- a/src/renderer/features/login/routes/login-route.tsx +++ b/src/renderer/features/login/routes/login-route.tsx @@ -6,6 +6,10 @@ import { Navigate } from 'react-router'; import { api } from '/@/renderer/api'; import { PageHeader } from '/@/renderer/components/page-header/page-header'; +import { + findExistingServerLockServer, + normalizeServerUrl, +} from '/@/renderer/features/action-required/utils/server-lock'; import { isLegacyAuth, isServerLock, @@ -19,6 +23,7 @@ import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-e import { AppRoute } from '/@/renderer/router/routes'; import { getServerById, + useAuthStore, useAuthStoreActions, useCurrentServer, useServerList, @@ -51,12 +56,10 @@ const SERVER_NAMES: Record = { [ServerType.SUBSONIC]: 'OpenSubsonic', }; -const normalizeUrl = (url: string) => url.replace(/\/$/, ''); - const LoginRoute = () => { const { t } = useTranslation(); const [isLoading, setIsLoading] = useState(false); - const { addServer, setCurrentServer, updateServer } = useAuthStoreActions(); + const { addServer, deleteServer, setCurrentServer, updateServer } = useAuthStoreActions(); const currentServer = useCurrentServer(); const serverList = useServerList(); @@ -151,15 +154,16 @@ const LoginRoute = () => { }); } - const normalizedUrl = normalizeUrl(serverUrl); - const normalizedRemoteURL = normalizeUrl(remoteUrl); - const existingServer = - serverLock && - Object.values(serverList).find((s) => normalizeUrl(s.url) === normalizedUrl); + const normalizedUrl = normalizeServerUrl(serverUrl); + const normalizedRemoteURL = normalizeServerUrl(remoteUrl); + const existingServer = serverLock + ? findExistingServerLockServer(serverList, normalizedUrl, serverType) + : undefined; + const serverId = existingServer?.id ?? nanoid(); const serverItem: ServerListItemWithCredential = { credential: data.credential, - id: nanoid(), + id: serverId, isAdmin: data.isAdmin, name: serverName, remoteUrl: normalizedRemoteURL, @@ -173,6 +177,9 @@ const LoginRoute = () => { const updates: Partial = { credential: data.credential, isAdmin: data.isAdmin, + name: serverName, + remoteUrl: normalizedRemoteURL, + url: normalizedUrl, userId: data.userId, username: data.username, }; @@ -190,12 +197,20 @@ const LoginRoute = () => { setCurrentServer(serverItem); } + if (serverLock) { + Object.values(useAuthStore.getState().serverList).forEach((server) => { + if (server.id !== serverId) { + deleteServer(server.id); + } + }); + } + toast.success({ message: t('form.addServer.success'), }); if (localSettings && values.password) { - const saved = await localSettings.passwordSet(values.password, serverItem.id); + const saved = await localSettings.passwordSet(values.password, serverId); if (!saved) { toast.error({ message: t('form.addServer.error', { diff --git a/src/renderer/router/app-outlet.tsx b/src/renderer/router/app-outlet.tsx index 3cf1bb6f3..f97a8f134 100644 --- a/src/renderer/router/app-outlet.tsx +++ b/src/renderer/router/app-outlet.tsx @@ -2,12 +2,11 @@ import { useEffect, useMemo } from 'react'; import { Navigate, Outlet } from 'react-router'; import { shallow } from 'zustand/shallow'; +import { normalizeServerUrl } from '/@/renderer/features/action-required/utils/server-lock'; import { isServerLock } from '/@/renderer/features/action-required/utils/window-properties'; import { AppRoute } from '/@/renderer/router/routes'; import { useAuthStore, useAuthStoreActions } from '/@/renderer/store'; -const normalizeUrl = (url: string) => url.replace(/\/$/, ''); - export const AppOutlet = () => { const currentServer = useAuthStore( (state) => @@ -19,25 +18,27 @@ export const AppOutlet = () => { : null, shallow, ); - const { deleteServer, setCurrentServer } = useAuthStoreActions(); + const { setCurrentServer, updateServer } = useAuthStoreActions(); const hasServerLockMismatch = useMemo(() => { if (!isServerLock() || !currentServer || !window.SERVER_URL) { return false; } - const configuredUrl = normalizeUrl(window.SERVER_URL); - const persistedUrl = normalizeUrl(currentServer.url); + const configuredUrl = normalizeServerUrl(window.SERVER_URL); + const persistedUrl = normalizeServerUrl(currentServer.url); return configuredUrl !== persistedUrl; }, [currentServer]); useEffect(() => { - if (hasServerLockMismatch && currentServer) { - deleteServer(currentServer.id); + if (hasServerLockMismatch && currentServer && window.SERVER_URL) { + updateServer(currentServer.id, { + url: normalizeServerUrl(window.SERVER_URL), + }); setCurrentServer(null); } - }, [currentServer, deleteServer, hasServerLockMismatch, setCurrentServer]); + }, [currentServer, hasServerLockMismatch, setCurrentServer, updateServer]); const isActionsRequired = !currentServer || hasServerLockMismatch;