mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
fix duplicate server add when SERVER_LOCK is configured (#1623)
This commit is contained in:
@@ -227,6 +227,7 @@
|
|||||||
"remotePortError": "an error occurred when trying to set the remote server port",
|
"remotePortError": "an error occurred when trying to set the remote server port",
|
||||||
"remotePortWarning": "restart the server to apply the new port",
|
"remotePortWarning": "restart the server to apply the new port",
|
||||||
"saveQueueFailed": "failed to save queue",
|
"saveQueueFailed": "failed to save queue",
|
||||||
|
"serverLockSingleServer": "only one server is allowed when server is locked",
|
||||||
"serverNotSelectedError": "no server selected",
|
"serverNotSelectedError": "no server selected",
|
||||||
"serverRequired": "server required",
|
"serverRequired": "server required",
|
||||||
"sessionExpiredError": "your session has expired",
|
"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 { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
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 { Button } from '/@/shared/components/button/button';
|
||||||
import { Center } from '/@/shared/components/center/center';
|
import { Center } from '/@/shared/components/center/center';
|
||||||
import { Code } from '/@/shared/components/code/code';
|
import { Code } from '/@/shared/components/code/code';
|
||||||
@@ -46,11 +51,14 @@ const SERVER_NAMES: Record<ServerType, string> = {
|
|||||||
[ServerType.SUBSONIC]: 'OpenSubsonic',
|
[ServerType.SUBSONIC]: 'OpenSubsonic',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const normalizeUrl = (url: string) => url.replace(/\/$/, '');
|
||||||
|
|
||||||
const LoginRoute = () => {
|
const LoginRoute = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { addServer, setCurrentServer } = useAuthStoreActions();
|
const { addServer, setCurrentServer, updateServer } = useAuthStoreActions();
|
||||||
const currentServer = useCurrentServer();
|
const currentServer = useCurrentServer();
|
||||||
|
const serverList = useServerList();
|
||||||
|
|
||||||
// Check if server lock is configured
|
// Check if server lock is configured
|
||||||
const serverLock = isServerLock();
|
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 = {
|
const serverItem: ServerListItemWithCredential = {
|
||||||
credential: data.credential,
|
credential: data.credential,
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
isAdmin: data.isAdmin,
|
isAdmin: data.isAdmin,
|
||||||
name: serverName,
|
name: serverName,
|
||||||
type: serverType as ServerType,
|
type: serverType as ServerType,
|
||||||
url: serverUrl.replace(/\/$/, ''),
|
url: normalizedUrl,
|
||||||
userId: data.userId,
|
userId: data.userId,
|
||||||
username: data.username,
|
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) {
|
if (data.ndCredential !== undefined) {
|
||||||
serverItem.ndCredential = data.ndCredential;
|
serverItem.ndCredential = data.ndCredential;
|
||||||
}
|
}
|
||||||
|
|
||||||
addServer(serverItem);
|
addServer(serverItem);
|
||||||
setCurrentServer(serverItem);
|
setCurrentServer(serverItem);
|
||||||
|
}
|
||||||
|
|
||||||
toast.success({
|
toast.success({
|
||||||
message: t('form.addServer.success', { postProcess: 'sentenceCase' }),
|
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 NavidromeIcon from '/@/renderer/features/servers/assets/navidrome.png';
|
||||||
import SubsonicIcon from '/@/renderer/features/servers/assets/opensubsonic.png';
|
import SubsonicIcon from '/@/renderer/features/servers/assets/opensubsonic.png';
|
||||||
import { IgnoreCorsSslSwitches } from '/@/renderer/features/servers/components/ignore-cors-ssl-switches';
|
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 { Checkbox } from '/@/shared/components/checkbox/checkbox';
|
||||||
import { Divider } from '/@/shared/components/divider/divider';
|
import { Divider } from '/@/shared/components/divider/divider';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
@@ -98,6 +98,7 @@ export const AddServerForm = ({ onCancel }: AddServerFormProps) => {
|
|||||||
const focusTrapRef = useFocusTrap(true);
|
const focusTrapRef = useFocusTrap(true);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { addServer, setCurrentServer } = useAuthStoreActions();
|
const { addServer, setCurrentServer } = useAuthStoreActions();
|
||||||
|
const serverList = useServerList();
|
||||||
const { servers: discovered } = useAutodiscovery();
|
const { servers: discovered } = useAutodiscovery();
|
||||||
|
|
||||||
const serverLock = isServerLock();
|
const serverLock = isServerLock();
|
||||||
@@ -128,6 +129,13 @@ export const AddServerForm = ({ onCancel }: AddServerFormProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = form.onSubmit(async (values) => {
|
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;
|
const authFunction = api.controller.authenticate;
|
||||||
|
|
||||||
if (!authFunction) {
|
if (!authFunction) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { openContextModal } from '@mantine/modals';
|
|||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import { useTranslation } from 'react-i18next';
|
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 JellyfinLogo from '/@/renderer/features/servers/assets/jellyfin.png';
|
||||||
import NavidromeLogo from '/@/renderer/features/servers/assets/navidrome.png';
|
import NavidromeLogo from '/@/renderer/features/servers/assets/navidrome.png';
|
||||||
import OpenSubsonicLogo from '/@/renderer/features/servers/assets/opensubsonic.png';
|
import OpenSubsonicLogo from '/@/renderer/features/servers/assets/opensubsonic.png';
|
||||||
@@ -23,6 +24,7 @@ export const ServerList = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const currentServer = useCurrentServer();
|
const currentServer = useCurrentServer();
|
||||||
const serverListQuery = useServerList();
|
const serverListQuery = useServerList();
|
||||||
|
const serverLock = isServerLock();
|
||||||
|
|
||||||
const handleAddServerModal = () => {
|
const handleAddServerModal = () => {
|
||||||
openContextModal({
|
openContextModal({
|
||||||
@@ -70,6 +72,7 @@ export const ServerList = () => {
|
|||||||
</Accordion.Item>
|
</Accordion.Item>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
{!serverLock && (
|
||||||
<Group grow pt="md">
|
<Group grow pt="md">
|
||||||
<Button
|
<Button
|
||||||
autoFocus
|
autoFocus
|
||||||
@@ -79,6 +82,7 @@ export const ServerList = () => {
|
|||||||
{t('form.addServer.title', { postProcess: 'titleCase' })}
|
{t('form.addServer.title', { postProcess: 'titleCase' })}
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
)}
|
||||||
</Accordion>
|
</Accordion>
|
||||||
{isElectron() && (
|
{isElectron() && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
Reference in New Issue
Block a user