150 lines
5.8 KiB
TypeScript
150 lines
5.8 KiB
TypeScript
/*
|
|
* Copyright (C) Contributors to the Suwayomi project
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
import { useState } from 'react';
|
|
import Stack from '@mui/material/Stack';
|
|
import Typography from '@mui/material/Typography';
|
|
import Button from '@mui/material/Button';
|
|
import { useLingui } from '@lingui/react/macro';
|
|
import {
|
|
IMAGE_PROCESSING_TYPE_TO_SETTING,
|
|
IMAGE_PROCESSING_TYPE_TO_TRANSLATION,
|
|
} from '@/features/settings/Settings.constants.ts';
|
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
|
import type { ImageProcessingType } from '@/features/settings/Settings.types.ts';
|
|
import { makeToast } from '@/base/utils/Toast.ts';
|
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
|
import { LoadingPlaceholder } from '@/base/components/feedback/LoadingPlaceholder.tsx';
|
|
import { EmptyViewAbsoluteCentered } from '@/base/components/feedback/EmptyViewAbsoluteCentered.tsx';
|
|
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
|
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
|
|
import {
|
|
addStableIdToConversions,
|
|
containsInvalidConversion,
|
|
didUpdateConversions,
|
|
isDuplicateConversion,
|
|
maybeAddDefault,
|
|
normalizeConversions,
|
|
toValidServerConversions,
|
|
} from '@/features/settings/ImageProcessing.utils.ts';
|
|
import { Processing } from '@/features/settings/components/images/Processing.tsx';
|
|
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
|
|
import type { PartialSettingsType } from '@/lib/graphql/generated/graphql-base.types.ts';
|
|
|
|
export const ImageProcessingSetting = ({ type }: { type: ImageProcessingType }) => {
|
|
const { t } = useLingui();
|
|
|
|
useAppTitle(t(IMAGE_PROCESSING_TYPE_TO_TRANSLATION[type]));
|
|
|
|
const { data, loading, error, refetch } = requestManager.useGetServerSettings();
|
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
|
|
|
const settingKey = IMAGE_PROCESSING_TYPE_TO_SETTING[type];
|
|
|
|
const conversions = data?.settings?.[settingKey] ?? STABLE_EMPTY_ARRAY;
|
|
|
|
const [tmpConversions, setTmpConversions] = useState(
|
|
normalizeConversions(maybeAddDefault(addStableIdToConversions(conversions))),
|
|
);
|
|
|
|
const hasInvalidConversion = containsInvalidConversion(tmpConversions);
|
|
const hasChanged = didUpdateConversions(
|
|
normalizeConversions(maybeAddDefault(addStableIdToConversions(conversions))),
|
|
tmpConversions,
|
|
);
|
|
|
|
const updateSetting = (value: PartialSettingsType[typeof settingKey]): Promise<any> => {
|
|
const mutation = mutateSettings({ variables: { input: { settings: { [settingKey]: value } } } });
|
|
mutation.catch((e) => makeToast(t`Failed to save changes`, 'error', getErrorMessage(e)));
|
|
|
|
return mutation;
|
|
};
|
|
|
|
const onSubmit = async () => {
|
|
try {
|
|
await updateSetting(toValidServerConversions(tmpConversions));
|
|
} catch (e) {
|
|
// ignore error
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return <LoadingPlaceholder />;
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<EmptyViewAbsoluteCentered
|
|
message={t`Unable to load data`}
|
|
messageExtra={getErrorMessage(error)}
|
|
retry={() => refetch().catch(defaultPromiseErrorHandler('ImageProcessingSetting::refetch'))}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Stack sx={{ p: 2, gap: 5 }}>
|
|
<Typography>
|
|
{t`In case no MIME-Type is defined, the "default" one will be used for the processing.\nSet the target mode to disabled to prevent processing for a MIME-Type`}
|
|
</Typography>
|
|
<Stack sx={{ flexDirection: 'column', gap: 5 }}>
|
|
{tmpConversions.map((conversion, index) => {
|
|
const { mimeType } = conversion;
|
|
|
|
const isDuplicate = isDuplicateConversion(mimeType, index, tmpConversions);
|
|
|
|
return (
|
|
<Processing
|
|
key={conversion.id}
|
|
conversion={conversion}
|
|
isDuplicate={isDuplicate}
|
|
onChange={(newConversion) => {
|
|
setTmpConversions((prev) =>
|
|
maybeAddDefault(
|
|
prev.toSpliced(index, 1, ...(newConversion ? [newConversion] : [])),
|
|
),
|
|
);
|
|
}}
|
|
/>
|
|
);
|
|
})}
|
|
</Stack>
|
|
<Stack
|
|
direction="row"
|
|
sx={{
|
|
gap: 1,
|
|
}}
|
|
>
|
|
<Button
|
|
variant="outlined"
|
|
onClick={() => {
|
|
setTmpConversions((prev) => [
|
|
...prev,
|
|
...addStableIdToConversions([
|
|
{
|
|
mimeType: '',
|
|
target: '',
|
|
compressionLevel: null,
|
|
headers: null,
|
|
callTimeout: null,
|
|
connectTimeout: null,
|
|
},
|
|
]),
|
|
]);
|
|
}}
|
|
>
|
|
{t`Add`}
|
|
</Button>
|
|
<Button variant="contained" disabled={hasInvalidConversion || !hasChanged} onClick={onSubmit}>
|
|
{t`Save`}
|
|
</Button>
|
|
</Stack>
|
|
</Stack>
|
|
);
|
|
};
|