Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plex settings: use the proper endpoints instead of patching settings #1070

Merged
merged 1 commit into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions src/components/Settings/MetadataSitesSettings/PlexSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import AnimateHeight from 'react-animate-height';
import { mdiLoading } from '@mdi/js';
import { Icon } from '@mdi/react';
import cx from 'classnames';
import { produce } from 'immer';
import { map, pull, toNumber } from 'lodash';

import Button from '@/components/Input/Button';
import Checkbox from '@/components/Input/Checkbox';
import SelectSmall from '@/components/Input/SelectSmall';
import toast from '@/components/Toast';
import { useInvalidatePlexTokenMutation } from '@/core/react-query/plex/mutations';
import {
useChangePlexLibrariesMutation,
useChangePlexServerMutation,
useInvalidatePlexTokenMutation,
} from '@/core/react-query/plex/mutations';
import {
usePlexLibrariesQuery,
usePlexLoginUrlQuery,
Expand Down Expand Up @@ -116,16 +119,16 @@ const PlexLinkButton = () => {
};

const PlexSettings = () => {
const { newSettings, setNewSettings } = useSettingsContext();
const { newSettings } = useSettingsContext();
const { Plex: plexSettings } = newSettings;

const [serverId, setServerId] = useState('');

const settings = useSettingsQuery().data;
const isAuthenticated = usePlexStatusQuery().data;
const serversQuery = usePlexServersQuery(isAuthenticated);
const librariesQuery = usePlexLibrariesQuery(isAuthenticated && serversQuery.isSuccess && !!serverId);
const { mutate: patchSettings } = usePatchSettingsMutation();
const librariesQuery = usePlexLibrariesQuery(isAuthenticated && serversQuery.isSuccess && !!plexSettings.Server);
const { mutate: changeServer } = useChangePlexServerMutation();
const { isPending: changeLibraryPending, mutate: changeLibraries } = useChangePlexLibrariesMutation();

useEffect(() => {
if (plexSettings.Server) setServerId(plexSettings.Server);
Expand All @@ -136,23 +139,23 @@ const PlexSettings = () => {
// Optimistic update
setServerId(event.target.value);

// We need to save it without pressing the save button to reload libraries.
patchSettings({ newSettings: { ...settings, Plex: { ...plexSettings, Server: event.target.value } } }, {
onSuccess: () => {
invalidateQueries(['plex', 'libraries']);
},
// Revert optimistic update if save fails
changeServer(event.target.value, {
onSuccess: () => invalidateQueries(['settings']),
onError: () => setServerId(plexSettings.Server),
});
});

const handleLibraryChange = useEventCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const key = toNumber(event.target.id);

const libraries = produce(plexSettings.Libraries, (draftState) => {
if (event.target.checked) draftState.push(key);
else pull(draftState, key);
});
const newLibraries = plexSettings.Libraries.slice();
if (event.target.checked) newLibraries.push(key);
else pull(newLibraries, key);

setNewSettings({ ...newSettings, Plex: { ...plexSettings, Libraries: libraries } });
changeLibraries(newLibraries, {
onSuccess: () => invalidateQueries(['settings']),
});
});

return (
Expand All @@ -177,9 +180,9 @@ const PlexSettings = () => {
</SelectSmall>
<AnimateHeight height={isAuthenticated && serversQuery.isSuccess && !!serverId ? 'auto' : 0}>
<div className="mb-2">Available Libraries</div>
<div className="flex flex-col gap-y-2 rounded-lg bg-panel-input px-4 py-2">
{librariesQuery.isPending && (
<div className="flex justify-center text-panel-text-primary">
<div className="relative flex min-h-10 flex-col gap-y-2 rounded-lg bg-panel-input px-4 py-2">
{(librariesQuery.isPending || changeLibraryPending) && (
<div className="absolute inset-0 flex items-center justify-center text-panel-text-primary">
<Icon path={mdiLoading} size={1} spin />
</div>
)}
Expand All @@ -201,6 +204,7 @@ const PlexSettings = () => {
isChecked={newSettings.Plex.Libraries.includes(library.Key)}
onChange={handleLibraryChange}
key={library.Key}
className={cx(changeLibraryPending && 'pointer-events-none opacity-65')}
/>
),
)}
Expand Down
16 changes: 16 additions & 0 deletions src/core/react-query/plex/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,19 @@ export const useInvalidatePlexTokenMutation = () =>
mutationFn: () => axios.get('token/invalidate'),
onSuccess: () => queryClient.resetQueries({ queryKey: ['plex', 'status'] }),
});

export const useChangePlexServerMutation = () =>
useMutation({
mutationFn: (serverId: string) =>
axios.post(
'server',
serverId,
{ headers: { 'Content-Type': 'application/json' } },
),
onSuccess: () => queryClient.resetQueries({ queryKey: ['plex', 'libraries'] }),
});

export const useChangePlexLibrariesMutation = () =>
useMutation({
mutationFn: (libraries: number[]) => axios.post('libraries', libraries),
});
2 changes: 1 addition & 1 deletion src/core/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function isDebug() {
return DEV;
}

export const minimumSupportedServerVersion = '4.2.2.152';
export const minimumSupportedServerVersion = '4.2.2.157';

export const parseServerVersion = (version: string) => {
const semverVersion = semver.coerce(version)?.raw;
Expand Down
7 changes: 5 additions & 2 deletions src/pages/settings/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import useMeasure from 'react-use-measure';
import { mdiLoading } from '@mdi/js';
import { Icon } from '@mdi/react';
import { isEqual } from 'lodash';
import { useDebounceValue } from 'usehooks-ts';

import Button from '@/components/Input/Button';
import toast from '@/components/Toast';
Expand Down Expand Up @@ -56,9 +57,11 @@ function SettingsPage() {
},
[newSettings, settings, settingsQuery.isSuccess],
);
const [debouncedUnsavedChanges] = useDebounceValue(unsavedChanges, 100);

// Use debounced value for unsaved changes to avoid flashing the toast for certain changes
useEffect(() => {
if (!unsavedChanges) {
if (!debouncedUnsavedChanges) {
if (toastId.current) toast.dismiss(toastId.current);
return;
}
Expand All @@ -68,7 +71,7 @@ function SettingsPage() {
'Please save before leaving this page.',
{ autoClose: false, position: 'top-right' },
);
}, [unsavedChanges]);
}, [debouncedUnsavedChanges]);

useEffect(() => () => {
if (toastId.current) toast.dismiss(toastId.current);
Expand Down
Loading