fix duplicate server add when SERVER_LOCK is configured (#1623)

This commit is contained in:
jeffvli
2026-02-13 19:42:36 -08:00
parent 2b4046a82e
commit dfbff64430
4 changed files with 58 additions and 18 deletions
+1
View File
@@ -227,6 +227,7 @@
"remotePortError": "an error occurred when trying to set the remote server port",
"remotePortWarning": "restart the server to apply the new port",
"saveQueueFailed": "failed to save queue",
"serverLockSingleServer": "only one server is allowed when server is locked",
"serverNotSelectedError": "no server selected",
"serverRequired": "server required",
"sessionExpiredError": "your session has expired",
@@ -17,7 +17,12 @@ import { IgnoreCorsSslSwitches } from '/@/renderer/features/servers/components/i
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
import { AppRoute } from '/@/renderer/router/routes';
import { useAuthStoreActions, useCurrentServer } from '/@/renderer/store';
import {
getServerById,
useAuthStoreActions,
useCurrentServer,
useServerList,
} from '/@/renderer/store';
import { Button } from '/@/shared/components/button/button';
import { Center } from '/@/shared/components/center/center';
import { Code } from '/@/shared/components/code/code';
@@ -46,11 +51,14 @@ const SERVER_NAMES: Record<ServerType, string> = {
[ServerType.SUBSONIC]: 'OpenSubsonic',
};
const normalizeUrl = (url: string) => url.replace(/\/$/, '');
const LoginRoute = () => {
const { t } = useTranslation();
const [isLoading, setIsLoading] = useState(false);
const { addServer, setCurrentServer } = useAuthStoreActions();
const { addServer, setCurrentServer, updateServer } = useAuthStoreActions();
const currentServer = useCurrentServer();
const serverList = useServerList();
// Check if server lock is configured
const serverLock = isServerLock();
@@ -141,23 +149,42 @@ const LoginRoute = () => {
});
}
const normalizedUrl = normalizeUrl(serverUrl);
const existingServer =
serverLock &&
Object.values(serverList).find((s) => normalizeUrl(s.url) === normalizedUrl);
const serverItem: ServerListItemWithCredential = {
credential: data.credential,
id: nanoid(),
isAdmin: data.isAdmin,
name: serverName,
type: serverType as ServerType,
url: serverUrl.replace(/\/$/, ''),
url: normalizedUrl,
userId: data.userId,
username: data.username,
};
if (existingServer) {
const updates: Partial<ServerListItemWithCredential> = {
credential: data.credential,
isAdmin: data.isAdmin,
userId: data.userId,
username: data.username,
};
if (data.ndCredential !== undefined) {
updates.ndCredential = data.ndCredential;
}
updateServer(existingServer.id, updates);
const updated = getServerById(existingServer.id);
if (updated) setCurrentServer(updated);
} else {
if (data.ndCredential !== undefined) {
serverItem.ndCredential = data.ndCredential;
}
addServer(serverItem);
setCurrentServer(serverItem);
}
toast.success({
message: t('form.addServer.success', { postProcess: 'sentenceCase' }),
@@ -13,7 +13,7 @@ import JellyfinIcon from '/@/renderer/features/servers/assets/jellyfin.png';
import NavidromeIcon from '/@/renderer/features/servers/assets/navidrome.png';
import SubsonicIcon from '/@/renderer/features/servers/assets/opensubsonic.png';
import { IgnoreCorsSslSwitches } from '/@/renderer/features/servers/components/ignore-cors-ssl-switches';
import { useAuthStoreActions } from '/@/renderer/store';
import { useAuthStoreActions, useServerList } from '/@/renderer/store';
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
import { Divider } from '/@/shared/components/divider/divider';
import { Group } from '/@/shared/components/group/group';
@@ -98,6 +98,7 @@ export const AddServerForm = ({ onCancel }: AddServerFormProps) => {
const focusTrapRef = useFocusTrap(true);
const [isLoading, setIsLoading] = useState(false);
const { addServer, setCurrentServer } = useAuthStoreActions();
const serverList = useServerList();
const { servers: discovered } = useAutodiscovery();
const serverLock = isServerLock();
@@ -128,6 +129,13 @@ export const AddServerForm = ({ onCancel }: AddServerFormProps) => {
};
const handleSubmit = form.onSubmit(async (values) => {
if (serverLock && Object.keys(serverList).length >= 1) {
toast.error({
message: t('error.serverLockSingleServer', { postProcess: 'sentenceCase' }),
});
return;
}
const authFunction = api.controller.authenticate;
if (!authFunction) {
@@ -2,6 +2,7 @@ import { openContextModal } from '@mantine/modals';
import isElectron from 'is-electron';
import { useTranslation } from 'react-i18next';
import { isServerLock } from '/@/renderer/features/action-required/utils/window-properties';
import JellyfinLogo from '/@/renderer/features/servers/assets/jellyfin.png';
import NavidromeLogo from '/@/renderer/features/servers/assets/navidrome.png';
import OpenSubsonicLogo from '/@/renderer/features/servers/assets/opensubsonic.png';
@@ -23,6 +24,7 @@ export const ServerList = () => {
const { t } = useTranslation();
const currentServer = useCurrentServer();
const serverListQuery = useServerList();
const serverLock = isServerLock();
const handleAddServerModal = () => {
openContextModal({
@@ -70,6 +72,7 @@ export const ServerList = () => {
</Accordion.Item>
);
})}
{!serverLock && (
<Group grow pt="md">
<Button
autoFocus
@@ -79,6 +82,7 @@ export const ServerList = () => {
{t('form.addServer.title', { postProcess: 'titleCase' })}
</Button>
</Group>
)}
</Accordion>
{isElectron() && (
<>