mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
Update server management
This commit is contained in:
@@ -8,7 +8,9 @@ import { AddServerUrlForm } from '@/renderer/features/servers/components/add-ser
|
|||||||
import { EditServerForm } from '@/renderer/features/servers/components/edit-server-form';
|
import { EditServerForm } from '@/renderer/features/servers/components/edit-server-form';
|
||||||
import { ServerSection } from '@/renderer/features/servers/components/server-section';
|
import { ServerSection } from '@/renderer/features/servers/components/server-section';
|
||||||
import { useDeleteServerUrl } from '@/renderer/features/servers/mutations/use-delete-server-url';
|
import { useDeleteServerUrl } from '@/renderer/features/servers/mutations/use-delete-server-url';
|
||||||
|
import { useDisableServerFolder } from '@/renderer/features/servers/mutations/use-disable-server-folder';
|
||||||
import { useDisableServerUrl } from '@/renderer/features/servers/mutations/use-disable-server-url';
|
import { useDisableServerUrl } from '@/renderer/features/servers/mutations/use-disable-server-url';
|
||||||
|
import { useEnableServerFolder } from '@/renderer/features/servers/mutations/use-enable-server-folder';
|
||||||
import { useEnableServerUrl } from '@/renderer/features/servers/mutations/use-enable-server-url';
|
import { useEnableServerUrl } from '@/renderer/features/servers/mutations/use-enable-server-url';
|
||||||
import { usePermissions } from '@/renderer/features/shared';
|
import { usePermissions } from '@/renderer/features/shared';
|
||||||
import { useAuthStore } from '@/renderer/store';
|
import { useAuthStore } from '@/renderer/store';
|
||||||
@@ -26,6 +28,8 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
|
|||||||
const enableServerUrl = useEnableServerUrl();
|
const enableServerUrl = useEnableServerUrl();
|
||||||
const disableServerUrl = useDisableServerUrl();
|
const disableServerUrl = useDisableServerUrl();
|
||||||
const deleteServerUrl = useDeleteServerUrl();
|
const deleteServerUrl = useDeleteServerUrl();
|
||||||
|
const enableServerFolder = useEnableServerFolder();
|
||||||
|
const disableServerFolder = useDisableServerFolder();
|
||||||
const serverCredentials = useAuthStore((state) => state.serverCredentials);
|
const serverCredentials = useAuthStore((state) => state.serverCredentials);
|
||||||
|
|
||||||
const enableServerCredential = useAuthStore(
|
const enableServerCredential = useAuthStore(
|
||||||
@@ -69,6 +73,18 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleToggleFolder = (folderId: string, enabled: boolean) => {
|
||||||
|
if (enabled) {
|
||||||
|
return disableServerFolder.mutate({
|
||||||
|
query: { folderId, serverId: server.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return enableServerFolder.mutate({
|
||||||
|
query: { folderId, serverId: server.id },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack spacing="xl">
|
<Stack spacing="xl">
|
||||||
@@ -104,7 +120,35 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
|
|||||||
</Group>
|
</Group>
|
||||||
)}
|
)}
|
||||||
</ServerSection>
|
</ServerSection>
|
||||||
<ServerSection title="Server URLs">
|
<ServerSection title="Music Folders">
|
||||||
|
<Stack>
|
||||||
|
{server.serverFolders?.map((folder) => (
|
||||||
|
<Group position="apart">
|
||||||
|
<Group>
|
||||||
|
<Text>{folder.name}</Text>
|
||||||
|
</Group>
|
||||||
|
<Group>
|
||||||
|
<Button
|
||||||
|
compact
|
||||||
|
radius="lg"
|
||||||
|
variant={folder.enabled ? 'filled' : 'subtle'}
|
||||||
|
onClick={() =>
|
||||||
|
handleToggleFolder(folder.id, folder.enabled)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{folder.enabled ? 'Enabled' : 'Disabled'}
|
||||||
|
</Button>
|
||||||
|
{permissions.deleteServerFolder && (
|
||||||
|
<Button compact disabled radius="xl" variant="subtle">
|
||||||
|
<RiDeleteBin2Fill />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</ServerSection>
|
||||||
|
<ServerSection title="URLs">
|
||||||
{addUrl ? (
|
{addUrl ? (
|
||||||
<AddServerUrlForm
|
<AddServerUrlForm
|
||||||
serverId={server.id}
|
serverId={server.id}
|
||||||
@@ -119,14 +163,13 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
|
|||||||
<Group>
|
<Group>
|
||||||
<Button
|
<Button
|
||||||
compact
|
compact
|
||||||
px={10}
|
|
||||||
radius="lg"
|
radius="lg"
|
||||||
variant={serverUrl.enabled ? 'filled' : 'subtle'}
|
variant={serverUrl.enabled ? 'filled' : 'subtle'}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleToggleUrl(serverUrl.id, serverUrl.enabled)
|
handleToggleUrl(serverUrl.id, serverUrl.enabled)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{serverUrl.enabled ? 'Disable' : 'Enable'}
|
{serverUrl.enabled ? 'Enabled' : 'Disabled'}
|
||||||
</Button>
|
</Button>
|
||||||
{permissions.deleteServerUrl && (
|
{permissions.deleteServerUrl && (
|
||||||
<Button
|
<Button
|
||||||
@@ -155,7 +198,7 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ServerSection>
|
</ServerSection>
|
||||||
<ServerSection title="Server Credentials">
|
<ServerSection title="Credentials">
|
||||||
{addCredential ? (
|
{addCredential ? (
|
||||||
<AddServerCredentialForm
|
<AddServerCredentialForm
|
||||||
server={server}
|
server={server}
|
||||||
@@ -170,7 +213,6 @@ export const ServerListItem = ({ server }: ServerListItemProps) => {
|
|||||||
<Group>
|
<Group>
|
||||||
<Button
|
<Button
|
||||||
compact
|
compact
|
||||||
px={10}
|
|
||||||
radius="lg"
|
radius="lg"
|
||||||
variant={credential.enabled ? 'filled' : 'subtle'}
|
variant={credential.enabled ? 'filled' : 'subtle'}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|||||||
@@ -18,9 +18,12 @@ const Section = styled.div`
|
|||||||
export const ServerSection = ({ title, children }: ServerSectionProps) => {
|
export const ServerSection = ({ title, children }: ServerSectionProps) => {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Text font={Font.EPILOGUE} size="sm">
|
{React.isValidElement(title) ? (
|
||||||
{title}
|
title
|
||||||
</Text>
|
) : (
|
||||||
|
<Text font={Font.EPILOGUE}>{title}</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
<Section>{children}</Section>
|
<Section>{children}</Section>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
|
import { api } from '@/renderer/api';
|
||||||
|
import { queryKeys } from '@/renderer/api/query-keys';
|
||||||
|
import { ServerListResponse } from '@/renderer/api/servers.api';
|
||||||
|
import { ApiError, NullResponse } from '@/renderer/api/types';
|
||||||
|
|
||||||
|
export const useDisableServerFolder = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const mutation = useMutation<
|
||||||
|
NullResponse,
|
||||||
|
AxiosError<ApiError>,
|
||||||
|
{ query: { folderId: string; serverId: string } },
|
||||||
|
{ previous: ServerListResponse | undefined }
|
||||||
|
>({
|
||||||
|
mutationFn: ({ query }) => api.servers.disableFolder(query),
|
||||||
|
onError: (_err, _variables, context) => {
|
||||||
|
if (!context?.previous) return;
|
||||||
|
queryClient.setQueryData(queryKeys.servers.list(), context.previous);
|
||||||
|
},
|
||||||
|
onMutate: async (variables) => {
|
||||||
|
const queryKey = queryKeys.servers.list();
|
||||||
|
|
||||||
|
await queryClient.cancelQueries(queryKey);
|
||||||
|
const previous = queryClient.getQueryData<ServerListResponse>(queryKey);
|
||||||
|
|
||||||
|
if (!previous) return undefined;
|
||||||
|
|
||||||
|
const data = previous.data.map((server) => {
|
||||||
|
if (server.id === variables.query.serverId) {
|
||||||
|
return {
|
||||||
|
...server,
|
||||||
|
serverFolders: server.serverFolders?.map((folder) =>
|
||||||
|
folder.id === variables.query.folderId
|
||||||
|
? { ...folder, enabled: false }
|
||||||
|
: folder
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
});
|
||||||
|
|
||||||
|
queryClient.setQueryData(queryKey, { ...previous, data });
|
||||||
|
|
||||||
|
return { previous };
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
queryClient.invalidateQueries(queryKeys.servers.list());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return mutation;
|
||||||
|
};
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
|
import { api } from '@/renderer/api';
|
||||||
|
import { queryKeys } from '@/renderer/api/query-keys';
|
||||||
|
import { ServerListResponse } from '@/renderer/api/servers.api';
|
||||||
|
import { ApiError, NullResponse } from '@/renderer/api/types';
|
||||||
|
|
||||||
|
export const useEnableServerFolder = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const mutation = useMutation<
|
||||||
|
NullResponse,
|
||||||
|
AxiosError<ApiError>,
|
||||||
|
{ query: { folderId: string; serverId: string } },
|
||||||
|
{ previous: ServerListResponse | undefined }
|
||||||
|
>({
|
||||||
|
mutationFn: ({ query }) => api.servers.enableFolder(query),
|
||||||
|
onError: (_err, _variables, context) => {
|
||||||
|
if (!context?.previous) return;
|
||||||
|
queryClient.setQueryData(queryKeys.servers.list(), context.previous);
|
||||||
|
},
|
||||||
|
onMutate: async (variables) => {
|
||||||
|
const queryKey = queryKeys.servers.list();
|
||||||
|
|
||||||
|
await queryClient.cancelQueries(queryKey);
|
||||||
|
const previous = queryClient.getQueryData<ServerListResponse>(queryKey);
|
||||||
|
|
||||||
|
if (!previous) return undefined;
|
||||||
|
|
||||||
|
const data = previous.data.map((server) => {
|
||||||
|
if (server.id === variables.query.serverId) {
|
||||||
|
return {
|
||||||
|
...server,
|
||||||
|
serverFolders: server.serverFolders?.map((folder) =>
|
||||||
|
folder.id === variables.query.folderId
|
||||||
|
? { ...folder, enabled: true }
|
||||||
|
: folder
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
});
|
||||||
|
|
||||||
|
queryClient.setQueryData(queryKey, { ...previous, data });
|
||||||
|
|
||||||
|
return { previous };
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
queryClient.invalidateQueries(queryKeys.servers.list());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return mutation;
|
||||||
|
};
|
||||||
@@ -20,7 +20,7 @@ export const validateServerCredential = async (options: {
|
|||||||
if (legacyAuth) {
|
if (legacyAuth) {
|
||||||
token = `u=${username}&p=${password}`;
|
token = `u=${username}&p=${password}`;
|
||||||
testConnection = await axios.get(
|
testConnection = await axios.get(
|
||||||
`${cleanServerUrl}/rest/ping.view?v=1.13.0&c=sonixd&f=json&${token}`
|
`${cleanServerUrl}/rest/ping.view?v=1.13.0&c=Feishin&f=json&${token}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const salt = randomString();
|
const salt = randomString();
|
||||||
@@ -28,7 +28,7 @@ export const validateServerCredential = async (options: {
|
|||||||
token = `u=${username}&s=${salt}&t=${hash}`;
|
token = `u=${username}&s=${salt}&t=${hash}`;
|
||||||
|
|
||||||
testConnection = await axios.get(
|
testConnection = await axios.get(
|
||||||
`${cleanServerUrl}/rest/ping.view?v=1.13.0&c=sonixd&f=json&${token}`
|
`${cleanServerUrl}/rest/ping.view?v=1.13.0&c=Feishin&f=json&${token}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ export const validateServerCredential = async (options: {
|
|||||||
{ pw: password, username },
|
{ pw: password, username },
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'X-Emby-Authorization': `MediaBrowser Client="Sonixd", Device="PC", DeviceId="Sonixd", Version="1.0.0-alpha1"`,
|
'X-Emby-Authorization': `MediaBrowser Client="Feishin", Device="PC", DeviceId="Feishin", Version="1.0.0-alpha1"`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user