Add WebUI settings (#460)
* Add WebUI settings * [VersionMapping] Require server version "r1427" for preview
This commit is contained in:
@@ -34,6 +34,7 @@ import { LibrarySettings } from '@/screens/settings/LibrarySettings';
|
|||||||
import { DefaultNavBar } from '@/components/navbar/DefaultNavBar';
|
import { DefaultNavBar } from '@/components/navbar/DefaultNavBar';
|
||||||
import { DownloadSettings } from '@/screens/settings/DownloadSettings.tsx';
|
import { DownloadSettings } from '@/screens/settings/DownloadSettings.tsx';
|
||||||
import { ServerSettings } from '@/screens/settings/ServerSettings.tsx';
|
import { ServerSettings } from '@/screens/settings/ServerSettings.tsx';
|
||||||
|
import { WebUISettings } from '@/screens/settings/WebUISettings.tsx';
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
// Adds messages only in a dev environment
|
// Adds messages only in a dev environment
|
||||||
@@ -68,6 +69,7 @@ export const App: React.FC = () => (
|
|||||||
<Route path="downloadSettings" element={<DownloadSettings />} />
|
<Route path="downloadSettings" element={<DownloadSettings />} />
|
||||||
<Route path="backup" element={<Backup />} />
|
<Route path="backup" element={<Backup />} />
|
||||||
<Route path="server" element={<ServerSettings />} />
|
<Route path="server" element={<ServerSettings />} />
|
||||||
|
<Route path="webUI" element={<WebUISettings />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* Manga Routes */}
|
{/* Manga Routes */}
|
||||||
|
|||||||
158
src/components/settings/SelectSetting.tsx
Normal file
158
src/components/settings/SelectSetting.tsx
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogTitle,
|
||||||
|
FormControl,
|
||||||
|
ListItemText,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
Stack,
|
||||||
|
Typography,
|
||||||
|
} from '@mui/material';
|
||||||
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
|
import DialogActions from '@mui/material/DialogActions';
|
||||||
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import DialogContentText from '@mui/material/DialogContentText';
|
||||||
|
import InfoIcon from '@mui/icons-material/Info';
|
||||||
|
import { TranslationKey } from '@/typings.ts';
|
||||||
|
|
||||||
|
export type SelectSettingValueDisplayInfo = {
|
||||||
|
text: TranslationKey;
|
||||||
|
description?: TranslationKey;
|
||||||
|
disclaimer?: TranslationKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SelectSettingValue<Value> = [Value: Value, DisplayInfo: SelectSettingValueDisplayInfo];
|
||||||
|
|
||||||
|
export const SelectSetting = <SettingValue extends string | number>({
|
||||||
|
settingName,
|
||||||
|
dialogDescription,
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
values,
|
||||||
|
handleChange,
|
||||||
|
disabled = false,
|
||||||
|
}: {
|
||||||
|
settingName: string;
|
||||||
|
dialogDescription?: string;
|
||||||
|
value?: SettingValue;
|
||||||
|
defaultValue: SettingValue;
|
||||||
|
values: SelectSettingValue<SettingValue>[];
|
||||||
|
handleChange: (value: SettingValue) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||||
|
const [dialogValue, setDialogValue] = useState(value ?? defaultValue);
|
||||||
|
|
||||||
|
const valueDisplayText = useMemo(() => values.find(([key]) => key === value)?.[1]?.text, [value]);
|
||||||
|
const dialogValueDisplayInfo = useMemo(() => values.find(([key]) => key === dialogValue)![1], [dialogValue]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDialogValue(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
const closeDialog = (resetValue: boolean = true) => {
|
||||||
|
if (resetValue) {
|
||||||
|
setDialogValue(value ?? defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSetting = () => {
|
||||||
|
closeDialog(false);
|
||||||
|
handleChange(dialogValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ListItemButton disabled={disabled} onClick={() => setIsDialogOpen(true)}>
|
||||||
|
<ListItemText
|
||||||
|
primary={settingName}
|
||||||
|
secondary={valueDisplayText ? t(valueDisplayText) : t('global.label.loading')}
|
||||||
|
secondaryTypographyProps={{ style: { display: 'flex', flexDirection: 'column' } }}
|
||||||
|
/>
|
||||||
|
</ListItemButton>
|
||||||
|
|
||||||
|
<Dialog open={isDialogOpen} onClose={() => closeDialog()} fullWidth>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogTitle sx={{ paddingLeft: 0 }}>{settingName}</DialogTitle>
|
||||||
|
{!!dialogDescription && (
|
||||||
|
<DialogContentText sx={{ paddingBottom: '10px' }}>{dialogDescription}</DialogContentText>
|
||||||
|
)}
|
||||||
|
{(!!dialogValueDisplayInfo.description || !!dialogValueDisplayInfo.disclaimer) && (
|
||||||
|
<DialogContentText sx={{ paddingBottom: '10px' }} component="div">
|
||||||
|
{dialogValueDisplayInfo.description && (
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
sx={{
|
||||||
|
whiteSpace: 'pre-line',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t(dialogValueDisplayInfo.description)}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{dialogValueDisplayInfo.disclaimer && (
|
||||||
|
<Stack direction="row" alignItems="center">
|
||||||
|
<InfoIcon color="warning" />
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
sx={{
|
||||||
|
marginLeft: '10px',
|
||||||
|
marginTop: '5px',
|
||||||
|
whiteSpace: 'pre-line',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t(dialogValueDisplayInfo.disclaimer)}
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</DialogContentText>
|
||||||
|
)}
|
||||||
|
{/* {!!dialogValueDisplayInfo.disclaimer && ( */}
|
||||||
|
{/* <DialogContentText sx={{ paddingBottom: '10px', color: 'orange' }}> */}
|
||||||
|
{/* {t(dialogValueDisplayInfo.disclaimer)} */}
|
||||||
|
{/* </DialogContentText> */}
|
||||||
|
{/* )} */}
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<Select
|
||||||
|
id="dialog-select"
|
||||||
|
value={dialogValue}
|
||||||
|
onChange={(e) => setDialogValue(e.target.value as SettingValue)}
|
||||||
|
>
|
||||||
|
{values.map(([selectValue, { text: selectText }]) => (
|
||||||
|
<MenuItem key={selectValue} value={selectValue}>
|
||||||
|
{t(selectText)}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => closeDialog()} color="primary">
|
||||||
|
{t('global.button.cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => updateSetting()} color="primary">
|
||||||
|
{t('global.button.ok')}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
84
src/components/settings/webUI/WebUIUpdateIntervalSetting.tsx
Normal file
84
src/components/settings/webUI/WebUIUpdateIntervalSetting.tsx
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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 { useTranslation } from 'react-i18next';
|
||||||
|
import { List, ListItem, ListItemText, Switch } from '@mui/material';
|
||||||
|
import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
||||||
|
import { getPersistedServerSetting, usePersistedValue } from '@/util/usePersistedValue.tsx';
|
||||||
|
|
||||||
|
const DEFAULT_VALUE = 23;
|
||||||
|
const MIN_VALUE = 1;
|
||||||
|
const MAX_VALUE = 23; // 1 month
|
||||||
|
|
||||||
|
export const WebUIUpdateIntervalSetting = ({ disabled = false }: { disabled?: boolean }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { data } = requestManager.useGetServerSettings();
|
||||||
|
const updateCheckInterval = data?.settings.webUIUpdateCheckInterval;
|
||||||
|
const shouldAutoUpdate = !!updateCheckInterval;
|
||||||
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
|
const [currentUpdateCheckInterval, persistUpdateCheckInterval] = usePersistedValue(
|
||||||
|
'lastUpdateCheckInterval',
|
||||||
|
DEFAULT_VALUE,
|
||||||
|
updateCheckInterval,
|
||||||
|
getPersistedServerSetting,
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateSetting = useCallback(
|
||||||
|
(webUIUpdateCheckInterval: number) => {
|
||||||
|
persistUpdateCheckInterval(
|
||||||
|
webUIUpdateCheckInterval === 0 ? currentUpdateCheckInterval : webUIUpdateCheckInterval,
|
||||||
|
);
|
||||||
|
mutateSettings({ variables: { input: { settings: { webUIUpdateCheckInterval } } } });
|
||||||
|
},
|
||||||
|
[currentUpdateCheckInterval],
|
||||||
|
);
|
||||||
|
|
||||||
|
const setDoAutoUpdates = (enable: boolean) => {
|
||||||
|
const globalUpdateInterval = enable ? currentUpdateCheckInterval : 0;
|
||||||
|
updateSetting(globalUpdateInterval);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List>
|
||||||
|
<ListItem disabled={disabled}>
|
||||||
|
<ListItemText primary={t('settings.webui.auto_update.label.title')} />
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<Switch
|
||||||
|
disabled={disabled}
|
||||||
|
edge="end"
|
||||||
|
checked={shouldAutoUpdate}
|
||||||
|
onChange={(e) => setDoAutoUpdates(e.target.checked)}
|
||||||
|
/>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
<NumberSetting
|
||||||
|
settingTitle={t('settings.webui.auto_update.label.interval')}
|
||||||
|
settingValue={
|
||||||
|
updateCheckInterval !== undefined
|
||||||
|
? t('library.settings.global_update.auto_update.interval.label.value', {
|
||||||
|
hours: currentUpdateCheckInterval,
|
||||||
|
})
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
value={currentUpdateCheckInterval}
|
||||||
|
minValue={MIN_VALUE}
|
||||||
|
maxValue={MAX_VALUE}
|
||||||
|
defaultValue={DEFAULT_VALUE}
|
||||||
|
showSlider
|
||||||
|
dialogTitle={t('settings.webui.auto_update.label.interval')}
|
||||||
|
valueUnit={t('global.time.hour_short')}
|
||||||
|
handleUpdate={updateSetting}
|
||||||
|
disabled={disabled || !shouldAutoUpdate}
|
||||||
|
/>
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -620,7 +620,84 @@
|
|||||||
"settings": "Server Settings"
|
"settings": "Server Settings"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Settings"
|
"title": "Settings",
|
||||||
|
"webui": {
|
||||||
|
"auto_update": {
|
||||||
|
"label": {
|
||||||
|
"interval": "Update interval",
|
||||||
|
"title": "Automatically download the latest version"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"channel": {
|
||||||
|
"label": {
|
||||||
|
"title": "Channel"
|
||||||
|
},
|
||||||
|
"option": {
|
||||||
|
"bundled": {
|
||||||
|
"label": {
|
||||||
|
"description": "Use the version that was delivered with the server release",
|
||||||
|
"title": "Bundled"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"label": {
|
||||||
|
"description": "Use the latest features and help us get them ready for a stable release.",
|
||||||
|
"disclaimer": "Features and changes in this version might not be completely ready yet and can cause bugs.\nMake sure that you have automatic backups enabled to prevent loss of your library!",
|
||||||
|
"title": "Preview"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stable": {
|
||||||
|
"label": {
|
||||||
|
"description": "Use the latest released version.",
|
||||||
|
"title": "Stable"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"electron_path": {
|
||||||
|
"label": {
|
||||||
|
"description": "The path to the electron installation on the server",
|
||||||
|
"title": "Electron path"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flavor": {
|
||||||
|
"label": {
|
||||||
|
"title": "Flavor"
|
||||||
|
},
|
||||||
|
"option": {
|
||||||
|
"custom": {
|
||||||
|
"label": {
|
||||||
|
"description": "Use a custom $t(settings.webui.title.webui).\nTo use a custom $t(settings.webui.title.webui) replace the content of the \"webUI\" directory in the root directory on the server with the files of the custom $t(settings.webui.title.webui)",
|
||||||
|
"title": "Custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"webui": {
|
||||||
|
"label": {
|
||||||
|
"description": "Use the default $t(settings.webui.title.webui)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"interface": {
|
||||||
|
"label": {
|
||||||
|
"description": "Where to start the $t(settings.webui.title.webui) when starting the server",
|
||||||
|
"title": "Interface"
|
||||||
|
},
|
||||||
|
"option": {
|
||||||
|
"label": {
|
||||||
|
"browser": "Browser",
|
||||||
|
"electron": "Electron"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"initial_open_browser": "Open the $t(settings.webui.title.webui) when starting the server"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"settings": "$t(settings.webui.title.webui) Settings",
|
||||||
|
"webui": "WebUI"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"source": {
|
"source": {
|
||||||
"configuration": {
|
"configuration": {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import CollectionsOutlinedBookmarkIcon from '@mui/icons-material/CollectionsBook
|
|||||||
import GetAppOutlinedIcon from '@mui/icons-material/GetAppOutlined';
|
import GetAppOutlinedIcon from '@mui/icons-material/GetAppOutlined';
|
||||||
import ViewModuleIcon from '@mui/icons-material/ViewModule';
|
import ViewModuleIcon from '@mui/icons-material/ViewModule';
|
||||||
import DnsIcon from '@mui/icons-material/Dns';
|
import DnsIcon from '@mui/icons-material/Dns';
|
||||||
|
import WebIcon from '@mui/icons-material/Web';
|
||||||
import { langCodeToName } from '@/util/language';
|
import { langCodeToName } from '@/util/language';
|
||||||
import { useLocalStorage } from '@/util/useLocalStorage';
|
import { useLocalStorage } from '@/util/useLocalStorage';
|
||||||
import { ListItemLink } from '@/components/util/ListItemLink';
|
import { ListItemLink } from '@/components/util/ListItemLink';
|
||||||
@@ -145,6 +146,12 @@ export function Settings() {
|
|||||||
</Select>
|
</Select>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
<ListItemLink to="/settings/webUI">
|
||||||
|
<ListItemIcon>
|
||||||
|
<WebIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary={t('settings.webui.title.webui')} />
|
||||||
|
</ListItemLink>
|
||||||
<ListItemLink to="/settings/server">
|
<ListItemLink to="/settings/server">
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<DnsIcon />
|
<DnsIcon />
|
||||||
|
|||||||
169
src/screens/settings/WebUISettings.tsx
Normal file
169
src/screens/settings/WebUISettings.tsx
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* 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 { useTranslation } from 'react-i18next';
|
||||||
|
import { useContext, useEffect } from 'react';
|
||||||
|
import List from '@mui/material/List';
|
||||||
|
import { ListItem, ListItemText, Switch } from '@mui/material';
|
||||||
|
import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction';
|
||||||
|
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext.tsx';
|
||||||
|
import { ServerSettings } from '@/typings.ts';
|
||||||
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
import { WebUIUpdateIntervalSetting } from '@/components/settings/webUI/WebUIUpdateIntervalSetting.tsx';
|
||||||
|
import { TextSetting } from '@/components/settings/TextSetting.tsx';
|
||||||
|
import {
|
||||||
|
SelectSetting,
|
||||||
|
SelectSettingValue,
|
||||||
|
SelectSettingValueDisplayInfo,
|
||||||
|
} from '@/components/settings/SelectSetting.tsx';
|
||||||
|
import { WebUiChannel, WebUiFlavor, WebUiInterface } from '@/lib/graphql/generated/graphql.ts';
|
||||||
|
|
||||||
|
type WebUISettingsType = Pick<
|
||||||
|
ServerSettings,
|
||||||
|
| 'webUIFlavor'
|
||||||
|
| 'initialOpenInBrowserEnabled'
|
||||||
|
| 'webUIInterface'
|
||||||
|
| 'electronPath'
|
||||||
|
| 'webUIChannel'
|
||||||
|
| 'webUIUpdateCheckInterval'
|
||||||
|
>;
|
||||||
|
|
||||||
|
const FLAVORS = Object.values(WebUiFlavor);
|
||||||
|
const FLAVOR_TO_TRANSLATION_KEY: { [flavor in WebUiFlavor]: SelectSettingValueDisplayInfo } = {
|
||||||
|
[WebUiFlavor.Webui]: {
|
||||||
|
text: 'settings.webui.title.webui',
|
||||||
|
description: 'settings.webui.flavor.option.webui.label.description',
|
||||||
|
},
|
||||||
|
[WebUiFlavor.Custom]: {
|
||||||
|
text: 'settings.webui.flavor.option.custom.label.title',
|
||||||
|
description: 'settings.webui.flavor.option.custom.label.description',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const FLAVOR_SELECT_VALUES: SelectSettingValue<WebUiFlavor>[] = FLAVORS.map((flavor) => [
|
||||||
|
flavor,
|
||||||
|
FLAVOR_TO_TRANSLATION_KEY[flavor],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const CHANNELS = Object.values(WebUiChannel);
|
||||||
|
const CHANNEL_TO_TRANSLATION_KEYS: {
|
||||||
|
[channel in WebUiChannel]: SelectSettingValueDisplayInfo;
|
||||||
|
} = {
|
||||||
|
[WebUiChannel.Bundled]: {
|
||||||
|
text: 'settings.webui.channel.option.bundled.label.title',
|
||||||
|
description: 'settings.webui.channel.option.bundled.label.description',
|
||||||
|
},
|
||||||
|
[WebUiChannel.Stable]: {
|
||||||
|
text: 'settings.webui.channel.option.stable.label.title',
|
||||||
|
description: 'settings.webui.channel.option.stable.label.description',
|
||||||
|
},
|
||||||
|
[WebUiChannel.Preview]: {
|
||||||
|
text: 'settings.webui.channel.option.preview.label.title',
|
||||||
|
description: 'settings.webui.channel.option.preview.label.description',
|
||||||
|
disclaimer: 'settings.webui.channel.option.preview.label.disclaimer',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const CHANNEL_SELECT_VALUES: SelectSettingValue<WebUiChannel>[] = CHANNELS.map((channel) => [
|
||||||
|
channel,
|
||||||
|
CHANNEL_TO_TRANSLATION_KEYS[channel],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const INTERFACES = Object.values(WebUiInterface);
|
||||||
|
const INTERFACE_TO_TRANSLATION_KEYS: {
|
||||||
|
[webUIInterface in WebUiInterface]: SelectSettingValueDisplayInfo;
|
||||||
|
} = {
|
||||||
|
[WebUiInterface.Browser]: {
|
||||||
|
text: 'settings.webui.interface.option.label.browser',
|
||||||
|
description: 'settings.webui.interface.label.description',
|
||||||
|
},
|
||||||
|
[WebUiInterface.Electron]: {
|
||||||
|
text: 'settings.webui.interface.option.label.electron',
|
||||||
|
description: 'settings.webui.interface.label.description',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const INTERFACE_SELECT_VALUES: SelectSettingValue<WebUiInterface>[] = INTERFACES.map((webUIInterface) => [
|
||||||
|
webUIInterface,
|
||||||
|
INTERFACE_TO_TRANSLATION_KEYS[webUIInterface],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const extractWebUISettings = (settings: ServerSettings): WebUISettingsType => ({
|
||||||
|
webUIFlavor: settings.webUIFlavor,
|
||||||
|
initialOpenInBrowserEnabled: settings.initialOpenInBrowserEnabled,
|
||||||
|
webUIInterface: settings.webUIInterface,
|
||||||
|
electronPath: settings.electronPath,
|
||||||
|
webUIChannel: settings.webUIChannel,
|
||||||
|
webUIUpdateCheckInterval: settings.webUIUpdateCheckInterval,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WebUISettings = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { setTitle, setAction } = useContext(NavBarContext);
|
||||||
|
|
||||||
|
useSetDefaultBackTo('settings');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTitle(t('settings.webui.title.settings'));
|
||||||
|
setAction(null);
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
const { data } = requestManager.useGetServerSettings();
|
||||||
|
const webUISettings = data ? extractWebUISettings(data.settings) : undefined;
|
||||||
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
|
|
||||||
|
const isDefaultWebUI = webUISettings?.webUIFlavor === WebUiFlavor.Webui;
|
||||||
|
|
||||||
|
const updateSetting = <Setting extends keyof WebUISettingsType>(
|
||||||
|
setting: Setting,
|
||||||
|
value: WebUISettingsType[Setting],
|
||||||
|
) => {
|
||||||
|
mutateSettings({ variables: { input: { settings: { [setting]: value } } } });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List>
|
||||||
|
<SelectSetting<WebUiFlavor>
|
||||||
|
settingName={t('settings.webui.flavor.label.title')}
|
||||||
|
value={webUISettings?.webUIFlavor}
|
||||||
|
defaultValue={WebUiFlavor.Webui}
|
||||||
|
values={FLAVOR_SELECT_VALUES}
|
||||||
|
handleChange={(flavor) => updateSetting('webUIFlavor', flavor)}
|
||||||
|
/>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText primary={t('settings.webui.label.initial_open_browser')} />
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<Switch
|
||||||
|
edge="end"
|
||||||
|
checked={!!webUISettings?.initialOpenInBrowserEnabled}
|
||||||
|
onChange={(e) => updateSetting('initialOpenInBrowserEnabled', e.target.checked)}
|
||||||
|
/>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
<SelectSetting<WebUiInterface>
|
||||||
|
settingName={t('settings.webui.interface.label.title')}
|
||||||
|
value={webUISettings?.webUIInterface}
|
||||||
|
defaultValue={WebUiInterface.Browser}
|
||||||
|
values={INTERFACE_SELECT_VALUES}
|
||||||
|
handleChange={(webUIInterface) => updateSetting('webUIInterface', webUIInterface)}
|
||||||
|
/>
|
||||||
|
<TextSetting
|
||||||
|
settingName={t('settings.webui.electron_path.label.title')}
|
||||||
|
dialogDescription={t('settings.webui.electron_path.label.description')}
|
||||||
|
value={webUISettings?.electronPath}
|
||||||
|
handleChange={(path) => updateSetting('electronPath', path)}
|
||||||
|
/>
|
||||||
|
<SelectSetting<WebUiChannel>
|
||||||
|
settingName={t('settings.webui.channel.label.title')}
|
||||||
|
value={webUISettings?.webUIChannel}
|
||||||
|
defaultValue={WebUiChannel.Stable}
|
||||||
|
values={CHANNEL_SELECT_VALUES}
|
||||||
|
handleChange={(channel) => updateSetting('webUIChannel', channel)}
|
||||||
|
disabled={!isDefaultWebUI}
|
||||||
|
/>
|
||||||
|
<WebUIUpdateIntervalSetting disabled={!isDefaultWebUI} />
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"uiVersion": "PREVIEW",
|
"uiVersion": "PREVIEW",
|
||||||
"serverVersion": "r1410"
|
"serverVersion": "r1427"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user