mirror of
https://github.com/C9Glax/tranga-website.git
synced 2025-04-12 14:38:21 +02:00
Backend Settings
This commit is contained in:
parent
2092db2ba3
commit
187dd22027
@ -58,7 +58,7 @@ export function getData(uri: string) : Promise<object> {
|
||||
return makeRequest("GET", uri, null) as Promise<object>;
|
||||
}
|
||||
|
||||
export function postData(uri: string, content: object | string | number) : Promise<object> {
|
||||
export function postData(uri: string, content: object | string | number | boolean) : Promise<object> {
|
||||
return makeRequest("POST", uri, content) as Promise<object>;
|
||||
}
|
||||
|
||||
@ -66,15 +66,15 @@ export function deleteData(uri: string) : Promise<void> {
|
||||
return makeRequest("DELETE", uri, null) as Promise<void>;
|
||||
}
|
||||
|
||||
export function patchData(uri: string, content: object | string | number) : Promise<object> {
|
||||
export function patchData(uri: string, content: object | string | number | boolean) : Promise<object> {
|
||||
return makeRequest("patch", uri, content) as Promise<object>;
|
||||
}
|
||||
|
||||
export function putData(uri: string, content: object | string | number) : Promise<object> {
|
||||
export function putData(uri: string, content: object | string | number | boolean) : Promise<object> {
|
||||
return makeRequest("PUT", uri, content) as Promise<object>;
|
||||
}
|
||||
|
||||
function makeRequest(method: string, uri: string, content: object | string | number | null) : Promise<object | void> {
|
||||
function makeRequest(method: string, uri: string, content: object | string | number | null | boolean) : Promise<object | void> {
|
||||
return fetch(uri,
|
||||
{
|
||||
method: method,
|
||||
@ -139,8 +139,8 @@ export const checkConnection = async (apiUri: string): Promise<boolean> =>{
|
||||
{
|
||||
method: 'GET',
|
||||
})
|
||||
.then((response) =>{
|
||||
return response.type != "error";
|
||||
.then((response) => {
|
||||
return response.ok;
|
||||
})
|
||||
.catch(() => {
|
||||
return Promise.reject();
|
||||
|
61
Website/modules/BackendSettingsFunctions.tsx
Normal file
61
Website/modules/BackendSettingsFunctions.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import {deleteData, getData, patchData} from "../App";
|
||||
import IRequestLimits, {RequestType} from "./interfaces/IRequestLimits";
|
||||
import IBackendSettings from "./interfaces/IBackendSettings";
|
||||
|
||||
export default class BackendSettings {
|
||||
static async GetSettings(apiUri: string) : Promise<IBackendSettings> {
|
||||
return getData(`${apiUri}/v2/Settings`).then((s) => s as IBackendSettings);
|
||||
}
|
||||
|
||||
static async GetUserAgent(apiUri: string) : Promise<string> {
|
||||
return getData(`${apiUri}/v2/Settings/UserAgent`).then((text) => text as unknown as string);
|
||||
}
|
||||
|
||||
static async UpdateUserAgent(apiUri: string, userAgent: string) {
|
||||
return patchData(`${apiUri}/v2/Settings/UserAgent`, userAgent);
|
||||
}
|
||||
|
||||
static async ResetUserAgent(apiUri: string) {
|
||||
return deleteData(`${apiUri}/v2/Settings/UserAgent`);
|
||||
}
|
||||
|
||||
static async GetRequestLimits(apiUri: string) : Promise<IRequestLimits> {
|
||||
return getData(`${apiUri}/v2/Settings/RequestLimits`).then((limits) => limits as IRequestLimits);
|
||||
}
|
||||
|
||||
static async ResetRequestLimits(apiUri: string) {
|
||||
return deleteData(`${apiUri}/v2/Settings/RequestLimits`);
|
||||
}
|
||||
|
||||
static async UpdateRequestLimit(apiUri: string, requestType: RequestType, value: number) {
|
||||
return patchData(`${apiUri}/v2/Settings/RequestLimits/${requestType}`, value);
|
||||
}
|
||||
|
||||
static async ResetRequestLimit(apiUri: string, requestType: RequestType) {
|
||||
return deleteData(`${apiUri}/v2/Settings/RequestLimits/${requestType}`);
|
||||
}
|
||||
|
||||
static async GetImageCompressionValue(apiUri: string) : Promise<number> {
|
||||
return getData(`${apiUri}/v2/Settings/ImageCompression`).then((n) => n as unknown as number);
|
||||
}
|
||||
|
||||
static async UpdateImageCompressionValue(apiUri: string, value: number) {
|
||||
return patchData(`${apiUri}/v2/Settings/ImageCompression`, value);
|
||||
}
|
||||
|
||||
static async GetBWImageToggle(apiUri: string) : Promise<boolean> {
|
||||
return getData(`${apiUri}/v2/Settings/BWImages`).then((state) => state as unknown as boolean);
|
||||
}
|
||||
|
||||
static async UpdateBWImageToggle(apiUri: string, value: boolean) {
|
||||
return patchData(`${apiUri}/v2/Settings/BWImages`, value);
|
||||
}
|
||||
|
||||
static async GetAprilFoolsToggle(apiUri: string) : Promise<boolean> {
|
||||
return getData(`${apiUri}/v2/Settings/AprilFoolsMode`).then((state) => state as unknown as boolean);
|
||||
}
|
||||
|
||||
static async UpdateAprilFoolsToggle(apiUri: string, value: boolean) {
|
||||
return patchData(`${apiUri}/v2/Settings/AprilFoolsMode`, value);
|
||||
}
|
||||
}
|
@ -1,22 +1,35 @@
|
||||
import IFrontendSettings from "./interfaces/IFrontendSettings";
|
||||
import '../styles/settings.css';
|
||||
import '../styles/react-toggle.css';
|
||||
import React, {useEffect, useState} from "react";
|
||||
import React, {LegacyRef, MutableRefObject, Ref, RefObject, useEffect, useRef, useState} from "react";
|
||||
import INotificationConnector, {NotificationConnectorItem} from "./interfaces/INotificationConnector";
|
||||
import NotificationConnectorFunctions from "./NotificationConnectorFunctions";
|
||||
import ILocalLibrary, {LocalLibraryItem} from "./interfaces/ILocalLibrary";
|
||||
import LocalLibraryFunctions from "./LocalLibraryFunctions";
|
||||
import IBackendSettings from "./interfaces/IBackendSettings";
|
||||
import BackendSettings from "./BackendSettingsFunctions";
|
||||
import Toggle from "react-toggle";
|
||||
import Loader from "./Loader";
|
||||
import {RequestType} from "./interfaces/IRequestLimits";
|
||||
|
||||
export default function Settings({backendConnected, apiUri, frontendSettings, setFrontendSettings} : {backendConnected: boolean, apiUri: string, frontendSettings: IFrontendSettings, setFrontendSettings: (settings: IFrontendSettings) => void}) {
|
||||
let [showSettings, setShowSettings] = useState<boolean>(false);
|
||||
let [notificationConnectors, setNotificationConnectors] = useState<INotificationConnector[]>([]);
|
||||
let [localLibraries, setLocalLibraries] = useState<ILocalLibrary[]>([]);
|
||||
export default function Settings({ backendConnected, apiUri, frontendSettings, setFrontendSettings } : {
|
||||
backendConnected: boolean,
|
||||
apiUri: string,
|
||||
frontendSettings: IFrontendSettings,
|
||||
setFrontendSettings: (settings: IFrontendSettings) => void
|
||||
}) {
|
||||
const [showSettings, setShowSettings] = useState<boolean>(false);
|
||||
const [loadingBackend, setLoadingBackend] = useState(false);
|
||||
const [backendSettings, setBackendSettings] = useState<IBackendSettings|null>(null);
|
||||
const [notificationConnectors, setNotificationConnectors] = useState<INotificationConnector[]>([]);
|
||||
const [localLibraries, setLocalLibraries] = useState<ILocalLibrary[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if(!backendConnected)
|
||||
return;
|
||||
NotificationConnectorFunctions.GetNotificationConnectors(apiUri).then(setNotificationConnectors);
|
||||
LocalLibraryFunctions.GetLibraries(apiUri).then(setLocalLibraries);
|
||||
BackendSettings.GetSettings(apiUri).then(setBackendSettings);
|
||||
}, [backendConnected, showSettings]);
|
||||
|
||||
const dateToStr = (x: Date) => {
|
||||
@ -26,6 +39,16 @@ export default function Settings({backendConnected, apiUri, frontendSettings, se
|
||||
return ret;
|
||||
}
|
||||
|
||||
const ChangeRequestLimit = (requestType: RequestType, limit: number) => {
|
||||
if(backendSettings === null)
|
||||
return;
|
||||
setLoadingBackend(true);
|
||||
BackendSettings.UpdateRequestLimit(apiUri, requestType, limit)
|
||||
.then(() => setBackendSettings({...backendSettings, [requestType]: requestType}))
|
||||
.finally(() => setLoadingBackend(false));
|
||||
}
|
||||
const ref : React.LegacyRef<HTMLInputElement> | undefined = useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<div id="Settings">
|
||||
<div onClick={() => setShowSettings(true)}>
|
||||
@ -38,14 +61,99 @@ export default function Settings({backendConnected, apiUri, frontendSettings, se
|
||||
<img alt="Close Settings" className="close" src="../media/close-x.svg" onClick={() => setShowSettings(false)}/>
|
||||
</div>
|
||||
<div id="SettingsPopUpBody" className="popupBody">
|
||||
<Loader loading={loadingBackend} style={{width: "64px", height: "64px", margin: "calc(sin(70)*(50% - 40px))", zIndex: 100, padding: 0, borderRadius: "50%", border: 0}}/>
|
||||
<div className="settings-apiuri">
|
||||
<label>ApiUri</label>
|
||||
<input type="url" defaultValue={frontendSettings.apiUri} onChange={(e) => setFrontendSettings({...frontendSettings, apiUri:e.currentTarget.value})} id="ApiUri" />
|
||||
</div>
|
||||
<div className="settings-apiuri">
|
||||
<div className="settings-jobinterval">
|
||||
<label>Default Job-Interval</label>
|
||||
<input type="time" min="00:30" max="23:59" defaultValue={dateToStr(new Date(frontendSettings.jobInterval))} onChange={(e) => setFrontendSettings({...frontendSettings, jobInterval: new Date(e.currentTarget.valueAsNumber-60*60*1000) ?? frontendSettings.jobInterval})}/>
|
||||
</div>
|
||||
<div className="settings-bwimages">
|
||||
<h3>B/W Images</h3>
|
||||
<Toggle defaultChecked={backendSettings ? backendSettings.bwImages : false} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => {
|
||||
if(backendSettings === null)
|
||||
return;
|
||||
setLoadingBackend(true);
|
||||
BackendSettings.UpdateBWImageToggle(apiUri, e.target.checked)
|
||||
.then(() => setBackendSettings({...backendSettings, bwImages: e.target.checked}))
|
||||
.finally(() => setLoadingBackend(false));
|
||||
}} />
|
||||
</div>
|
||||
<div className="settings-aprilfools">
|
||||
<h3>April Fools Mode</h3>
|
||||
<Toggle defaultChecked={backendSettings ? backendSettings.aprilFoolsMode : false} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => {
|
||||
if(backendSettings === null)
|
||||
return;
|
||||
setLoadingBackend(true);
|
||||
BackendSettings.UpdateAprilFoolsToggle(apiUri, e.target.checked)
|
||||
.then(() => setBackendSettings({...backendSettings, aprilFoolsMode: e.target.checked}))
|
||||
.finally(() => setLoadingBackend(false));
|
||||
}} />
|
||||
</div>
|
||||
<div className="settings-imagecompression">
|
||||
<h3>Image Compression</h3>
|
||||
<Toggle defaultChecked={backendSettings ? backendSettings.compression < 100 : false} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => {
|
||||
if(backendSettings === null)
|
||||
return;
|
||||
setLoadingBackend(true);
|
||||
BackendSettings.UpdateImageCompressionValue(apiUri, e.target.checked ? 40 : 100)
|
||||
.then(() => setBackendSettings({...backendSettings, compression: e.target.checked ? 40 : 100}))
|
||||
.then(() => {
|
||||
if(ref.current != null){
|
||||
ref.current.value = e.target.checked ? "40" : "100";
|
||||
ref.current.disabled = !e.target.checked;
|
||||
}
|
||||
})
|
||||
.finally(() => setLoadingBackend(false));
|
||||
}} />
|
||||
<input ref={ref} type="number" min={0} max={100} defaultValue={backendSettings ? backendSettings.compression : 0} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => {
|
||||
if(backendSettings === null)
|
||||
return;
|
||||
setLoadingBackend(true);
|
||||
BackendSettings.UpdateImageCompressionValue(apiUri, e.currentTarget.valueAsNumber)
|
||||
.then(() => setBackendSettings({...backendSettings, compression: e.currentTarget.valueAsNumber}))
|
||||
.finally(() => setLoadingBackend(false));
|
||||
}} />
|
||||
</div>
|
||||
<div className="settings-requestLimits">
|
||||
<h3>Request Limits:</h3>
|
||||
<label htmlFor="Default">Default</label>
|
||||
<input id="Default" type="number" defaultValue={backendSettings ? backendSettings.requestLimits.Default : 0} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => ChangeRequestLimit(RequestType.Default, e.currentTarget.valueAsNumber)} />
|
||||
<label htmlFor="MangaInfo">MangaInfo</label>
|
||||
<input id="MangaInfo" type="number" defaultValue={backendSettings ? backendSettings.requestLimits.MangaInfo : 0} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => ChangeRequestLimit(RequestType.MangaInfo, e.currentTarget.valueAsNumber)} />
|
||||
<label htmlFor="MangaDexFeed">MangaDexFeed</label>
|
||||
<input id="MangaDexFeed" type="number" defaultValue={backendSettings ? backendSettings.requestLimits.MangaDexFeed : 0} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => ChangeRequestLimit(RequestType.MangaDexFeed, e.currentTarget.valueAsNumber)} />
|
||||
<label htmlFor="MangaDexImage">MangaDexImage</label>
|
||||
<input id="MangaDexImage" type="number" defaultValue={backendSettings ? backendSettings.requestLimits.MangaDexImage : 0} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => ChangeRequestLimit(RequestType.MangaDexImage, e.currentTarget.valueAsNumber)} />
|
||||
<label htmlFor="MangaImage">MangaImage</label>
|
||||
<input id="MangaImage" type="number" defaultValue={backendSettings ? backendSettings.requestLimits.MangaImage : 0} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => ChangeRequestLimit(RequestType.MangaImage, e.currentTarget.valueAsNumber)} />
|
||||
<label htmlFor="MangaCover">MangaCover</label>
|
||||
<input id="MangaCover" type="number" defaultValue={backendSettings ? backendSettings.requestLimits.MangaCover : 0} disabled={backendSettings ? false : !loadingBackend}
|
||||
onChange={(e) => ChangeRequestLimit(RequestType.MangaCover, e.currentTarget.valueAsNumber)} />
|
||||
</div>
|
||||
<div className="settings-useragent">
|
||||
<label>User Agent</label>
|
||||
<input type="text" defaultValue={backendSettings ? backendSettings.userAgent : ""}
|
||||
onSubmit={(e) => {
|
||||
if(backendSettings === null)
|
||||
return;
|
||||
setLoadingBackend(true);
|
||||
BackendSettings.UpdateUserAgent(apiUri, e.currentTarget.value)
|
||||
.then(() => setBackendSettings({...backendSettings, userAgent: e.currentTarget.value}))
|
||||
.finally(() => setLoadingBackend(false));
|
||||
}} />
|
||||
</div>
|
||||
<h3>Notification Connectors:</h3>
|
||||
{notificationConnectors.map(c => <NotificationConnectorItem apiUri={apiUri} notificationConnector={c} key={c.name} />)}
|
||||
<NotificationConnectorItem apiUri={apiUri} notificationConnector={null} key="New Notification Connector" />
|
||||
|
@ -1,15 +0,0 @@
|
||||
export default interface IBackendSettings {
|
||||
"downloadLocation": string;
|
||||
"userAgent": string;
|
||||
"aprilFoolsMode": boolean;
|
||||
"compression": number;
|
||||
"bwImages": boolean;
|
||||
"requestLimits": {
|
||||
"MangaInfo": number;
|
||||
"MangaDexFeed": number;
|
||||
"MangaDexImage": number;
|
||||
"MangaImage": number;
|
||||
"MangaCover": number;
|
||||
"Default": number
|
||||
}
|
||||
}
|
17
Website/modules/interfaces/IBackendSettings.tsx
Normal file
17
Website/modules/interfaces/IBackendSettings.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
export default interface IBackendSettings {
|
||||
downloadLocation: string;
|
||||
workingDirectory: string;
|
||||
userAgent: string;
|
||||
aprilFoolsMode: boolean;
|
||||
requestLimits: {
|
||||
Default: number,
|
||||
MangaInfo: number,
|
||||
MangaDexFeed: number,
|
||||
MangaDexImage: number,
|
||||
MangaImage: number,
|
||||
MangaCover: number,
|
||||
};
|
||||
compression: number;
|
||||
bwImages: boolean;
|
||||
startNewJobTimeoutMs: number;
|
||||
}
|
17
Website/modules/interfaces/IRequestLimits.ts
Normal file
17
Website/modules/interfaces/IRequestLimits.ts
Normal file
@ -0,0 +1,17 @@
|
||||
export default interface IRequestLimits {
|
||||
Default: number;
|
||||
MangaDexFeed: number;
|
||||
MangaImage: number;
|
||||
MangaCover: number;
|
||||
MangaDexImage: number;
|
||||
MangaInfo: number;
|
||||
}
|
||||
|
||||
export enum RequestType {
|
||||
Default = "Default",
|
||||
MangaDexFeed = "MangaDexFeed",
|
||||
MangaImage = "MangaImage",
|
||||
MangaCover = "MangaCover",
|
||||
MangaDexImage = "MangaDexImage",
|
||||
MangaInfo = "MangaInfo"
|
||||
}
|
@ -40,5 +40,8 @@
|
||||
left: 0;
|
||||
width: calc(100% - 30px);
|
||||
height: calc(100% - 50px);
|
||||
margin: 5px 15px;
|
||||
padding: 5px 15px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
scrollbar-width: thin;
|
||||
}
|
@ -43,6 +43,15 @@
|
||||
|
||||
#SettingsPopUpBody h1, #SettingsPopUpBody h2, #SettingsPopUpBody h3 {
|
||||
border: 0;
|
||||
margin: 5px 0 0 0;
|
||||
margin: 5px 0 2px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.settings-requestLimits {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.settings-requestLimits input {
|
||||
width: min-content;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user