Add "ui login" support
This commit is contained in:
@@ -63,6 +63,7 @@
|
|||||||
"i18next": "25.3.6",
|
"i18next": "25.3.6",
|
||||||
"i18next-browser-languagedetector": "8.2.0",
|
"i18next-browser-languagedetector": "8.2.0",
|
||||||
"i18next-http-backend": "3.0.2",
|
"i18next-http-backend": "3.0.2",
|
||||||
|
"js-cookie": "^3.0.5",
|
||||||
"jsonrepair": "3.13.0",
|
"jsonrepair": "3.13.0",
|
||||||
"material-ui-popup-state": "5.3.6",
|
"material-ui-popup-state": "5.3.6",
|
||||||
"mui-nested-menu": "4.0.1",
|
"mui-nested-menu": "4.0.1",
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
"@graphql-codegen/typescript-apollo-client-helpers": "3.0.1",
|
"@graphql-codegen/typescript-apollo-client-helpers": "3.0.1",
|
||||||
"@graphql-codegen/typescript-operations": "4.6.1",
|
"@graphql-codegen/typescript-operations": "4.6.1",
|
||||||
"@types/apollo-upload-client": "18.0.0",
|
"@types/apollo-upload-client": "18.0.0",
|
||||||
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node": "24.3.0",
|
"@types/node": "24.3.0",
|
||||||
"@types/react": "19.1.10",
|
"@types/react": "19.1.10",
|
||||||
"@types/react-beautiful-dnd": "13.1.8",
|
"@types/react-beautiful-dnd": "13.1.8",
|
||||||
|
|||||||
@@ -116,9 +116,9 @@
|
|||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"action": {
|
"action": {
|
||||||
|
"all": "Mark all as read",
|
||||||
"current": "Mark as read",
|
"current": "Mark as read",
|
||||||
"previous": "Mark previous as read",
|
"previous": "Mark previous as read"
|
||||||
"all": "Mark all as read"
|
|
||||||
},
|
},
|
||||||
"confirmation_one": "You are about to mark one chapter as read",
|
"confirmation_one": "You are about to mark one chapter as read",
|
||||||
"confirmation_other": "You are about to mark {{count}} chapters as read",
|
"confirmation_other": "You are about to mark {{count}} chapters as read",
|
||||||
@@ -521,6 +521,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
|
"days": {
|
||||||
|
"day_one": "Day",
|
||||||
|
"day_other": "Days",
|
||||||
|
"value": "{{count}} $t(global.time.days.day, lowercase)"
|
||||||
|
},
|
||||||
"hour_short": "h",
|
"hour_short": "h",
|
||||||
"minutes": {
|
"minutes": {
|
||||||
"minute_one": "Minute",
|
"minute_one": "Minute",
|
||||||
@@ -1297,6 +1302,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
|
"jwt": {
|
||||||
|
"access_token_expiry": "JWT access token expiry",
|
||||||
|
"audience": "JWT audience claim",
|
||||||
|
"refresh_token_expiry": "JWT refresh token expiry"
|
||||||
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"password": "$t(global.label.password)",
|
"password": "$t(global.label.password)",
|
||||||
"title": "Authentication Mode",
|
"title": "Authentication Mode",
|
||||||
@@ -1317,12 +1327,18 @@
|
|||||||
"title": "None"
|
"title": "None"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"simpleLogin": {
|
"simple_login": {
|
||||||
"label": {
|
"label": {
|
||||||
"description": "A simple login page will be presented to login.",
|
"description": "The login will be handled by the server.",
|
||||||
"info": "When you enable this, you may need to refresh this tab for the login page to appear.",
|
"info": "When you enable this, you may need to refresh this tab for the login page to appear.",
|
||||||
"title": "Simple Login"
|
"title": "Simple Login"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ui_login": {
|
||||||
|
"label": {
|
||||||
|
"description": "The login will be handled by the client.",
|
||||||
|
"title": "UI Login"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
181
src/App.tsx
181
src/App.tsx
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import CssBaseline from '@mui/material/CssBaseline';
|
import CssBaseline from '@mui/material/CssBaseline';
|
||||||
import React, { useLayoutEffect } from 'react';
|
import React, { useLayoutEffect } from 'react';
|
||||||
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
import { Navigate, Outlet, Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import { loadErrorMessages, loadDevMessages } from '@apollo/client/dev';
|
import { loadErrorMessages, loadDevMessages } from '@apollo/client/dev';
|
||||||
import { loadable } from 'react-lazily/loadable';
|
import { loadable } from 'react-lazily/loadable';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
@@ -27,6 +27,10 @@ import { AppRoutes } from '@/base/AppRoute.constants.ts';
|
|||||||
import { useMetadataServerSettings } from '@/features/settings/services/ServerSettingsMetadata.ts';
|
import { useMetadataServerSettings } from '@/features/settings/services/ServerSettingsMetadata.ts';
|
||||||
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
|
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
|
||||||
import { BrowseTab } from '@/features/browse/Browse.types.ts';
|
import { BrowseTab } from '@/features/browse/Browse.types.ts';
|
||||||
|
import { useSessionContext } from '@/features/authentication/SessionContext.tsx';
|
||||||
|
import { LoginPage } from '@/features/authentication/screens/LoginPage.tsx';
|
||||||
|
import { AuthGuard } from '@/features/authentication/components/AuthGuard.tsx';
|
||||||
|
import { SearchParam } from '@/base/Base.types.ts';
|
||||||
|
|
||||||
const { Browse } = loadable(() => import('@/features/browse/screens/Browse.tsx'), lazyLoadFallback);
|
const { Browse } = loadable(() => import('@/features/browse/screens/Browse.tsx'), lazyLoadFallback);
|
||||||
const { DownloadQueue } = loadable(() => import('@/features/downloads/screens/DownloadQueue.tsx'), lazyLoadFallback);
|
const { DownloadQueue } = loadable(() => import('@/features/downloads/screens/DownloadQueue.tsx'), lazyLoadFallback);
|
||||||
@@ -82,7 +86,7 @@ const { More } = loadable(() => import('@/features/settings/screens/More.tsx'),
|
|||||||
const { Reader } = loadable(() => import('@/features/reader/screens/Reader.tsx'), lazyLoadFallback);
|
const { Reader } = loadable(() => import('@/features/reader/screens/Reader.tsx'), lazyLoadFallback);
|
||||||
const { HistorySettings } = loadable(() => import('@/features/history/screens/HistorySettings.tsx'), lazyLoadFallback);
|
const { HistorySettings } = loadable(() => import('@/features/history/screens/HistorySettings.tsx'), lazyLoadFallback);
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (import.meta.env.DEV) {
|
||||||
// Adds messages only in a dev environment
|
// Adds messages only in a dev environment
|
||||||
loadDevMessages();
|
loadDevMessages();
|
||||||
loadErrorMessages();
|
loadErrorMessages();
|
||||||
@@ -105,15 +109,39 @@ const ScrollToTop = () => {
|
|||||||
* and thus, data of existing chapters/mangas in the cache get outdated
|
* and thus, data of existing chapters/mangas in the cache get outdated
|
||||||
*/
|
*/
|
||||||
const BackgroundSubscriptions = () => {
|
const BackgroundSubscriptions = () => {
|
||||||
// load the full download status once on startup to fill the cache
|
// Listen to session changes
|
||||||
|
const { isAuthRequired, accessToken } = useSessionContext();
|
||||||
|
|
||||||
|
const skipConnection = isAuthRequired == null || (!!isAuthRequired && !accessToken);
|
||||||
|
|
||||||
|
// Load the full download status once on startup to fill the cache
|
||||||
requestManager.useGetDownloadStatus({ nextFetchPolicy: 'standby' });
|
requestManager.useGetDownloadStatus({ nextFetchPolicy: 'standby' });
|
||||||
requestManager.useDownloadSubscription();
|
requestManager.useDownloadSubscription({ skip: skipConnection });
|
||||||
requestManager.useUpdaterSubscription();
|
requestManager.useUpdaterSubscription({ skip: skipConnection });
|
||||||
requestManager.useWebUIUpdateSubscription();
|
requestManager.useWebUIUpdateSubscription({ skip: skipConnection });
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PrivateRoutes = () => {
|
||||||
|
const { isAuthRequired, accessToken, refreshToken } = useSessionContext();
|
||||||
|
|
||||||
|
const isAuthenticated = !isAuthRequired || (isAuthRequired && (accessToken || refreshToken));
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return (
|
||||||
|
<Navigate
|
||||||
|
to={{
|
||||||
|
pathname: AppRoutes.authentication.childRoutes.login.path,
|
||||||
|
search: `${SearchParam.REDIRECT}=${window.location.pathname}`,
|
||||||
|
}}
|
||||||
|
replace
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Outlet />;
|
||||||
|
};
|
||||||
|
|
||||||
const MainApp = () => {
|
const MainApp = () => {
|
||||||
const { navBarWidth, appBarHeight, bottomBarHeight } = useNavBarContext();
|
const { navBarWidth, appBarHeight, bottomBarHeight } = useNavBarContext();
|
||||||
const isMobileWidth = MediaQuery.useIsMobileWidth();
|
const isMobileWidth = MediaQuery.useIsMobileWidth();
|
||||||
@@ -139,60 +167,87 @@ const MainApp = () => {
|
|||||||
>
|
>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Routes>
|
<Routes>
|
||||||
{/* General Routes */}
|
<Route path={AppRoutes.authentication.match}>
|
||||||
<Route path={AppRoutes.root.match} element={<Navigate to={AppRoutes.library.path()} replace />} />
|
<Route path={AppRoutes.authentication.childRoutes.login.match} element={<LoginPage />} />
|
||||||
<Route path={AppRoutes.matchAll.match} element={<Navigate to={AppRoutes.root.path} replace />} />
|
</Route>
|
||||||
{isMobileWidth && <Route path={AppRoutes.more.match} element={<More />} />}
|
|
||||||
<Route path={AppRoutes.about.match} element={<About />} />
|
<Route element={<PrivateRoutes />}>
|
||||||
<Route path={AppRoutes.settings.match}>
|
{/* General Routes */}
|
||||||
<Route index element={<Settings />} />
|
<Route
|
||||||
<Route path={AppRoutes.settings.childRoutes.categories.match} element={<CategorySettings />} />
|
path={AppRoutes.root.match}
|
||||||
<Route path={AppRoutes.settings.childRoutes.reader.match} element={<GlobalReaderSettings />} />
|
element={<Navigate to={AppRoutes.library.path()} replace />}
|
||||||
<Route path={AppRoutes.settings.childRoutes.library.match}>
|
/>
|
||||||
<Route index element={<LibrarySettings />} />
|
<Route
|
||||||
|
path={AppRoutes.matchAll.match}
|
||||||
|
element={<Navigate to={AppRoutes.root.path} replace />}
|
||||||
|
/>
|
||||||
|
{isMobileWidth && <Route path={AppRoutes.more.match} element={<More />} />}
|
||||||
|
<Route path={AppRoutes.about.match} element={<About />} />
|
||||||
|
<Route path={AppRoutes.settings.match}>
|
||||||
|
<Route index element={<Settings />} />
|
||||||
<Route
|
<Route
|
||||||
path={AppRoutes.settings.childRoutes.library.childRoutes.duplicates.match}
|
path={AppRoutes.settings.childRoutes.categories.match}
|
||||||
element={<LibraryDuplicates />}
|
element={<CategorySettings />}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path={AppRoutes.settings.childRoutes.reader.match}
|
||||||
|
element={<GlobalReaderSettings />}
|
||||||
|
/>
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.library.match}>
|
||||||
|
<Route index element={<LibrarySettings />} />
|
||||||
|
<Route
|
||||||
|
path={AppRoutes.settings.childRoutes.library.childRoutes.duplicates.match}
|
||||||
|
element={<LibraryDuplicates />}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
<Route
|
||||||
|
path={AppRoutes.settings.childRoutes.download.match}
|
||||||
|
element={<DownloadSettings />}
|
||||||
|
/>
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.backup.match} element={<Backup />} />
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.server.match} element={<ServerSettings />} />
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.webui.match} element={<WebUISettings />} />
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.browse.match} element={<BrowseSettings />} />
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.history.match} element={<HistorySettings />} />
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.device.match} element={<DeviceSetting />} />
|
||||||
|
<Route
|
||||||
|
path={AppRoutes.settings.childRoutes.tracking.match}
|
||||||
|
element={<TrackingSettings />}
|
||||||
|
/>
|
||||||
|
<Route path={AppRoutes.settings.childRoutes.appearance.match} element={<Appearance />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={AppRoutes.settings.childRoutes.download.match} element={<DownloadSettings />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.backup.match} element={<Backup />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.server.match} element={<ServerSettings />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.webui.match} element={<WebUISettings />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.browse.match} element={<BrowseSettings />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.history.match} element={<HistorySettings />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.device.match} element={<DeviceSetting />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.tracking.match} element={<TrackingSettings />} />
|
|
||||||
<Route path={AppRoutes.settings.childRoutes.appearance.match} element={<Appearance />} />
|
|
||||||
</Route>
|
|
||||||
|
|
||||||
{/* Manga Routes */}
|
{/* Manga Routes */}
|
||||||
|
|
||||||
<Route path={AppRoutes.sources.match}>
|
<Route path={AppRoutes.sources.match}>
|
||||||
{/* TODO: deprecated - "source" and "extension" page got merged into "browse" */}
|
{/* TODO: deprecated - "source" and "extension" page got merged into "browse" */}
|
||||||
<Route index element={<Navigate to={AppRoutes.browse.path(BrowseTab.SOURCES)} replace />} />
|
<Route index element={<Navigate to={AppRoutes.browse.path(BrowseTab.SOURCES)} replace />} />
|
||||||
<Route path={AppRoutes.sources.childRoutes.browse.match} element={<SourceMangas />} />
|
<Route path={AppRoutes.sources.childRoutes.browse.match} element={<SourceMangas />} />
|
||||||
<Route path={AppRoutes.sources.childRoutes.configure.match} element={<SourceConfigure />} />
|
<Route path={AppRoutes.sources.childRoutes.configure.match} element={<SourceConfigure />} />
|
||||||
<Route path={AppRoutes.sources.childRoutes.searchAll.match} element={<SearchAll />} />
|
<Route path={AppRoutes.sources.childRoutes.searchAll.match} element={<SearchAll />} />
|
||||||
|
</Route>
|
||||||
|
<Route path={AppRoutes.extension.match}>
|
||||||
|
<Route
|
||||||
|
index
|
||||||
|
element={<Navigate to={AppRoutes.browse.path(BrowseTab.EXTENSIONS)} replace />}
|
||||||
|
/>
|
||||||
|
<Route path={AppRoutes.extension.childRoutes.info.match} element={<ExtensionInfo />} />
|
||||||
|
</Route>
|
||||||
|
<Route path={AppRoutes.downloads.match} element={<DownloadQueue />} />
|
||||||
|
<Route path={AppRoutes.manga.match}>
|
||||||
|
<Route path={AppRoutes.manga.childRoutes.reader.match} element={null} />
|
||||||
|
<Route index element={<Manga />} />
|
||||||
|
</Route>
|
||||||
|
<Route path={AppRoutes.library.match} element={<Library />} />
|
||||||
|
<Route path={AppRoutes.updates.match} element={<Updates />} />
|
||||||
|
{!hideHistory && <Route path={AppRoutes.history.match} element={<History />} />}
|
||||||
|
<Route path={AppRoutes.browse.match} element={<Browse />} />
|
||||||
|
<Route path={AppRoutes.migrate.match}>
|
||||||
|
<Route index element={<Migrate />} />
|
||||||
|
<Route path={AppRoutes.migrate.childRoutes.search.match} element={<SearchAll />} />
|
||||||
|
</Route>
|
||||||
|
<Route path={AppRoutes.tracker.match} element={<TrackerOAuthLogin />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={AppRoutes.extension.match}>
|
|
||||||
<Route index element={<Navigate to={AppRoutes.browse.path(BrowseTab.EXTENSIONS)} replace />} />
|
|
||||||
<Route path={AppRoutes.extension.childRoutes.info.match} element={<ExtensionInfo />} />
|
|
||||||
</Route>
|
|
||||||
<Route path={AppRoutes.downloads.match} element={<DownloadQueue />} />
|
|
||||||
<Route path={AppRoutes.manga.match}>
|
|
||||||
<Route path={AppRoutes.manga.childRoutes.reader.match} element={null} />
|
|
||||||
<Route index element={<Manga />} />
|
|
||||||
</Route>
|
|
||||||
<Route path={AppRoutes.library.match} element={<Library />} />
|
|
||||||
<Route path={AppRoutes.updates.match} element={<Updates />} />
|
|
||||||
{!hideHistory && <Route path={AppRoutes.history.match} element={<History />} />}
|
|
||||||
<Route path={AppRoutes.browse.match} element={<Browse />} />
|
|
||||||
<Route path={AppRoutes.migrate.match}>
|
|
||||||
<Route index element={<Migrate />} />
|
|
||||||
<Route path={AppRoutes.migrate.childRoutes.search.match} element={<SearchAll />} />
|
|
||||||
</Route>
|
|
||||||
<Route path={AppRoutes.tracker.match} element={<TrackerOAuthLogin />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -214,14 +269,16 @@ export const App: React.FC = () => (
|
|||||||
<WebUIUpdateChecker />
|
<WebUIUpdateChecker />
|
||||||
<BackgroundSubscriptions />
|
<BackgroundSubscriptions />
|
||||||
<CssBaseline enableColorScheme />
|
<CssBaseline enableColorScheme />
|
||||||
<Box sx={{ display: 'flex' }}>
|
<AuthGuard>
|
||||||
<Box sx={{ flexShrink: 0, position: 'relative', height: '100vh' }}>
|
<Box sx={{ display: 'flex' }}>
|
||||||
<DefaultNavBar />
|
<Box sx={{ flexShrink: 0, position: 'relative', height: '100vh' }}>
|
||||||
|
<DefaultNavBar />
|
||||||
|
</Box>
|
||||||
|
<Routes>
|
||||||
|
<Route path={AppRoutes.matchAll.match} element={<MainApp />} />
|
||||||
|
<Route path={AppRoutes.reader.match} element={<ReaderApp />} />
|
||||||
|
</Routes>
|
||||||
</Box>
|
</Box>
|
||||||
<Routes>
|
</AuthGuard>
|
||||||
<Route path={AppRoutes.matchAll.match} element={<MainApp />} />
|
|
||||||
<Route path={AppRoutes.reader.match} element={<ReaderApp />} />
|
|
||||||
</Routes>
|
|
||||||
</Box>
|
|
||||||
</AppContext>
|
</AppContext>
|
||||||
);
|
);
|
||||||
|
|||||||
31
src/assets/SuwayomiLogo.tsx
Normal file
31
src/assets/SuwayomiLogo.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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 SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
|
||||||
|
|
||||||
|
export const SuwayomiLogo = ({
|
||||||
|
circleRingColor = '#35d4d5',
|
||||||
|
...props
|
||||||
|
}: SvgIconProps & { circleRingColor?: string }) => (
|
||||||
|
<SvgIcon {...props}>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="100">
|
||||||
|
<svg version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="50" cy="50" r="50" fill={circleRingColor} />
|
||||||
|
<circle cx="50" cy="50" r="39" fill="#1A1A1D" />
|
||||||
|
<path
|
||||||
|
d="m26.46 38.07 15.633-.27c3.348-.081 3.348-.081 4.482.783.783.972 1.161 1.701 1.404 2.916-.216 1.053-.567 1.593-1.242 2.403l-3.321 4.509c-.513.702-.513.702-.756 1.539.216.108.216.108.459.189 2.322 1.269 4.347 3.402 6.291 5.211l1.539 1.431c.459.621.594 1.053.621 1.809l-2.268 2.619c-.675.54-1.188.459-2.052.351-.702-.513-.702-.513-1.404-1.242l-3.861-3.996c-.81-.837-1.674-1.593-2.565-2.322-.972.459-1.62.999-2.376 1.728-7.29 6.723-7.29 6.723-10.206 6.615-1.161-.432-1.998-1.215-2.808-2.133-.27-.918-.27-.918-.27-1.62 1.08-.918 2.187-1.755 3.402-2.457 4.428-2.592 8.046-6.183 11.124-10.287 1.026-1.431 1.35-1.998 1.674-2.646l-12.15.054c-.54-.054-.54-.054-1.08-.594-.243-1.107-.27-2.16-.27-3.24l0-1.35z"
|
||||||
|
fill="#fdfdfd"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="m78.6486 37.8378 1.5405 1.5135c-.5405 8.027-5.4324 16.1892-10.8649 21.8378-1.4054 1.4324-1.8649 1.8919-3.0811 2.1081-.9459-.1892-1.6757-.4324-2.5405-.8378l-1.3514-.6757c-.1081-1.2162-.1081-1.2162.3243-1.8378l3.2432-3.0811c3.8919-3.8919 6.1892-9.2703 7.5135-14.5405h-11.6216v7.8378c-.6216.2973-.973.2973-1.6486.2973-3.7297 0-3.7297 0-4.027-.2973v-13.2432l18.4865-.2973c1.6216.027 2.8378.0541 4.027 1.2162z"
|
||||||
|
fill="#f9f9f9"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</svg>
|
||||||
|
</SvgIcon>
|
||||||
|
);
|
||||||
@@ -38,13 +38,23 @@ export const AppRoutes = {
|
|||||||
matchAll: {
|
matchAll: {
|
||||||
match: '*',
|
match: '*',
|
||||||
},
|
},
|
||||||
|
authentication: {
|
||||||
|
match: 'auth',
|
||||||
|
path: '/auth',
|
||||||
|
childRoutes: {
|
||||||
|
login: {
|
||||||
|
match: 'login',
|
||||||
|
path: '/auth/login',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
about: {
|
about: {
|
||||||
match: 'about',
|
match: 'about',
|
||||||
path: '/about',
|
path: '/about',
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
path: '/settings',
|
|
||||||
match: 'settings',
|
match: 'settings',
|
||||||
|
path: '/settings',
|
||||||
childRoutes: {
|
childRoutes: {
|
||||||
categories: {
|
categories: {
|
||||||
match: 'categories',
|
match: 'categories',
|
||||||
|
|||||||
@@ -71,4 +71,5 @@ export enum ScrollDirection {
|
|||||||
export enum SearchParam {
|
export enum SearchParam {
|
||||||
TAB = 'tab',
|
TAB = 'tab',
|
||||||
QUERY = 'query',
|
QUERY = 'query',
|
||||||
|
REDIRECT = 'redirect',
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/base/components/AvatarSpinner.tsx
Normal file
30
src/base/components/AvatarSpinner.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 Avatar, { AvatarProps } from '@mui/material/Avatar';
|
||||||
|
import { SpinnerImage, SpinnerImageProps } from '@/base/components/SpinnerImage.tsx';
|
||||||
|
|
||||||
|
export const AvatarSpinner = ({
|
||||||
|
iconUrl,
|
||||||
|
alt,
|
||||||
|
slots,
|
||||||
|
}: {
|
||||||
|
iconUrl: string;
|
||||||
|
alt: string;
|
||||||
|
slots?: { avatarProps?: Partial<AvatarProps>; spinnerImageProps?: Partial<SpinnerImageProps> };
|
||||||
|
}) => (
|
||||||
|
<Avatar variant="rounded" alt={alt} {...slots?.avatarProps}>
|
||||||
|
<SpinnerImage
|
||||||
|
alt={alt}
|
||||||
|
src={iconUrl}
|
||||||
|
{...slots?.spinnerImageProps}
|
||||||
|
spinnerStyle={{ small: true, ...slots?.spinnerImageProps?.spinnerStyle }}
|
||||||
|
imgStyle={{ objectFit: 'cover', width: '100%', height: '100%', ...slots?.spinnerImageProps?.imgStyle }}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
);
|
||||||
@@ -6,36 +6,28 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Avatar, { AvatarProps } from '@mui/material/Avatar';
|
import { ComponentProps } from 'react';
|
||||||
import { SpinnerImage, SpinnerImageProps } from '@/base/components/SpinnerImage.tsx';
|
import { AvatarSpinner } from '@/base/components/AvatarSpinner.tsx';
|
||||||
|
|
||||||
export const ListCardAvatar = ({
|
export const ListCardAvatar = (props: ComponentProps<typeof AvatarSpinner>) => {
|
||||||
iconUrl,
|
const { slots } = props;
|
||||||
alt,
|
|
||||||
slots,
|
return (
|
||||||
}: {
|
<AvatarSpinner
|
||||||
iconUrl: string;
|
{...props}
|
||||||
alt: string;
|
slots={{
|
||||||
slots?: { avatarProps?: Partial<AvatarProps>; spinnerImageProps?: Partial<SpinnerImageProps> };
|
...slots,
|
||||||
}) => (
|
avatarProps: {
|
||||||
<Avatar
|
...slots?.avatarProps,
|
||||||
variant="rounded"
|
sx: {
|
||||||
alt={alt}
|
width: 56,
|
||||||
{...slots?.avatarProps}
|
height: 56,
|
||||||
sx={{
|
flex: '0 0 auto',
|
||||||
width: 56,
|
background: 'transparent',
|
||||||
height: 56,
|
...slots?.avatarProps?.sx,
|
||||||
flex: '0 0 auto',
|
},
|
||||||
background: 'transparent',
|
},
|
||||||
...slots?.avatarProps?.sx,
|
}}
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SpinnerImage
|
|
||||||
alt={alt}
|
|
||||||
src={iconUrl}
|
|
||||||
{...slots?.spinnerImageProps}
|
|
||||||
spinnerStyle={{ small: true, ...slots?.spinnerImageProps?.spinnerStyle }}
|
|
||||||
imgStyle={{ objectFit: 'cover', width: '100%', height: '100%', ...slots?.spinnerImageProps?.imgStyle }}
|
|
||||||
/>
|
/>
|
||||||
</Avatar>
|
);
|
||||||
);
|
};
|
||||||
|
|||||||
@@ -19,37 +19,40 @@ import { SnackbarWithDescription } from '@/base/components/feedback/SnackbarWith
|
|||||||
import { AppPageHistoryContextProvider } from '@/base/contexts/AppPageHistoryContext.tsx';
|
import { AppPageHistoryContextProvider } from '@/base/contexts/AppPageHistoryContext.tsx';
|
||||||
import { AppThemeContextProvider } from '@/features/theme/AppThemeContext.tsx';
|
import { AppThemeContextProvider } from '@/features/theme/AppThemeContext.tsx';
|
||||||
import { NavBarContextProvider } from '@/features/navigation-bar/NavbarContext.tsx';
|
import { NavBarContextProvider } from '@/features/navigation-bar/NavbarContext.tsx';
|
||||||
|
import { SessionContextProvider } from '@/features/authentication/SessionContext.tsx';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppContext: React.FC<Props> = ({ children }) => (
|
export const AppContext: React.FC<Props> = ({ children }) => (
|
||||||
<Router>
|
<SessionContextProvider>
|
||||||
<StyledEngineProvider injectFirst>
|
<Router>
|
||||||
<AppThemeContextProvider>
|
<StyledEngineProvider injectFirst>
|
||||||
<QueryParamProvider adapter={ReactRouter6Adapter}>
|
<AppThemeContextProvider>
|
||||||
<NavBarContextProvider>
|
<QueryParamProvider adapter={ReactRouter6Adapter}>
|
||||||
<AppPageHistoryContextProvider>
|
<NavBarContextProvider>
|
||||||
<ActiveDeviceContextProvider>
|
<AppPageHistoryContextProvider>
|
||||||
<SnackbarProvider
|
<ActiveDeviceContextProvider>
|
||||||
Components={{
|
<SnackbarProvider
|
||||||
default: SnackbarWithDescription,
|
Components={{
|
||||||
info: SnackbarWithDescription,
|
default: SnackbarWithDescription,
|
||||||
success: SnackbarWithDescription,
|
info: SnackbarWithDescription,
|
||||||
warning: SnackbarWithDescription,
|
success: SnackbarWithDescription,
|
||||||
error: SnackbarWithDescription,
|
warning: SnackbarWithDescription,
|
||||||
}}
|
error: SnackbarWithDescription,
|
||||||
>
|
}}
|
||||||
<ReaderContextProvider>
|
>
|
||||||
<AppHotkeysProvider>{children}</AppHotkeysProvider>
|
<ReaderContextProvider>
|
||||||
</ReaderContextProvider>
|
<AppHotkeysProvider>{children}</AppHotkeysProvider>
|
||||||
</SnackbarProvider>
|
</ReaderContextProvider>
|
||||||
</ActiveDeviceContextProvider>
|
</SnackbarProvider>
|
||||||
</AppPageHistoryContextProvider>
|
</ActiveDeviceContextProvider>
|
||||||
</NavBarContextProvider>
|
</AppPageHistoryContextProvider>
|
||||||
</QueryParamProvider>
|
</NavBarContextProvider>
|
||||||
</AppThemeContextProvider>
|
</QueryParamProvider>
|
||||||
</StyledEngineProvider>
|
</AppThemeContextProvider>
|
||||||
</Router>
|
</StyledEngineProvider>
|
||||||
|
</Router>
|
||||||
|
</SessionContextProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
93
src/features/authentication/AuthManager.ts
Normal file
93
src/features/authentication/AuthManager.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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 { AppStorage } from '@/lib/storage/AppStorage.ts';
|
||||||
|
import { useSessionStorage } from '@/base/hooks/useStorage.tsx';
|
||||||
|
|
||||||
|
export class AuthManager {
|
||||||
|
static readonly AUTH_REQUIRED_KEY = 'auth-required';
|
||||||
|
|
||||||
|
static readonly REFRESH_TOKEN_KEY = 'auth-refresh-token';
|
||||||
|
|
||||||
|
static readonly REACT_SESSION_REFRESH_KEY = 'auth-react-session-refresh';
|
||||||
|
|
||||||
|
private static accessToken: string | null = null;
|
||||||
|
|
||||||
|
static isAuthRequired(): boolean | null {
|
||||||
|
return AppStorage.session.getItemParsed(AuthManager.AUTH_REQUIRED_KEY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static setAuthRequired(value: boolean | null): void {
|
||||||
|
AppStorage.session.setItem(AuthManager.AUTH_REQUIRED_KEY, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static useIsAuthRequired(): boolean | null {
|
||||||
|
const [value] = useSessionStorage(AuthManager.AUTH_REQUIRED_KEY, null);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getAccessToken(): string | null {
|
||||||
|
return AuthManager.accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getRefreshToken(): string | null {
|
||||||
|
return AppStorage.session.getItemParsed(AuthManager.REFRESH_TOKEN_KEY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getTokens(): { accessToken: string | null; refreshToken: string | null } {
|
||||||
|
return {
|
||||||
|
accessToken: AuthManager.getAccessToken(),
|
||||||
|
refreshToken: AuthManager.getRefreshToken(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static setAccessToken(token: string): void {
|
||||||
|
AuthManager.accessToken = token;
|
||||||
|
AuthManager.refreshReactSessionContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
static setRefreshToken(token: string): void {
|
||||||
|
AppStorage.session.setItem(AuthManager.REFRESH_TOKEN_KEY, token);
|
||||||
|
AuthManager.refreshReactSessionContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
static setTokens(accessToken: string, refreshToken: string): void {
|
||||||
|
AuthManager.setAccessToken(accessToken);
|
||||||
|
AuthManager.setRefreshToken(refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
static removeAccessToken(): void {
|
||||||
|
AuthManager.accessToken = null;
|
||||||
|
AuthManager.refreshReactSessionContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
static removeRefreshToken(): void {
|
||||||
|
AppStorage.session.setItem(AuthManager.REFRESH_TOKEN_KEY, undefined);
|
||||||
|
AuthManager.refreshReactSessionContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
static removeTokens(): void {
|
||||||
|
AuthManager.removeAccessToken();
|
||||||
|
AuthManager.removeRefreshToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getNextReactSessionContextId(): number {
|
||||||
|
const id = AppStorage.session.getItemParsed(AuthManager.REACT_SESSION_REFRESH_KEY, 0);
|
||||||
|
|
||||||
|
return (id + 1) % Number.MAX_SAFE_INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static refreshReactSessionContext(): void {
|
||||||
|
AppStorage.session.setItem(AuthManager.REACT_SESSION_REFRESH_KEY, AuthManager.getNextReactSessionContextId());
|
||||||
|
}
|
||||||
|
|
||||||
|
static useListenToReactSessionContextRefreshEvent(): void {
|
||||||
|
useSessionStorage(AuthManager.REACT_SESSION_REFRESH_KEY, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/features/authentication/SessionContext.tsx
Normal file
42
src/features/authentication/SessionContext.tsx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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 { createContext, ReactNode, useContext, useMemo } from 'react';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
|
||||||
|
interface TSessionContext {
|
||||||
|
isAuthRequired: boolean | null;
|
||||||
|
accessToken: string | null;
|
||||||
|
refreshToken: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SessionContext = createContext<TSessionContext>({
|
||||||
|
isAuthRequired: null,
|
||||||
|
accessToken: null,
|
||||||
|
refreshToken: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SessionContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
|
AuthManager.useListenToReactSessionContextRefreshEvent();
|
||||||
|
|
||||||
|
const isAuthRequired = AuthManager.useIsAuthRequired();
|
||||||
|
const { accessToken, refreshToken } = AuthManager.getTokens();
|
||||||
|
|
||||||
|
const value = useMemo(
|
||||||
|
() => ({
|
||||||
|
isAuthRequired,
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
}),
|
||||||
|
[isAuthRequired, accessToken, refreshToken],
|
||||||
|
);
|
||||||
|
|
||||||
|
return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSessionContext = () => useContext(SessionContext);
|
||||||
36
src/features/authentication/components/AuthGuard.tsx
Normal file
36
src/features/authentication/components/AuthGuard.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 { ReactNode, useEffect } from 'react';
|
||||||
|
import { useSessionContext } from '@/features/authentication/SessionContext.tsx';
|
||||||
|
import { SplashScreen } from '@/features/authentication/components/SplashScreen.tsx';
|
||||||
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
|
||||||
|
export const AuthGuard = ({ children }: { children: ReactNode }) => {
|
||||||
|
const { isAuthRequired } = useSessionContext();
|
||||||
|
|
||||||
|
requestManager.useGetAbout({
|
||||||
|
skip: isAuthRequired !== null,
|
||||||
|
onCompleted: () => AuthManager.setAuthRequired(false),
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onUnload = () => AuthManager.setAuthRequired(null);
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', onUnload);
|
||||||
|
|
||||||
|
return () => window.removeEventListener('beforeunload', onUnload);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (isAuthRequired === null) {
|
||||||
|
return <SplashScreen />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
};
|
||||||
46
src/features/authentication/components/SplashScreen.tsx
Normal file
46
src/features/authentication/components/SplashScreen.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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 { useTheme } from '@mui/material/styles';
|
||||||
|
import Stack from '@mui/material/Stack';
|
||||||
|
import { SuwayomiLogo } from '@/assets/SuwayomiLogo.tsx';
|
||||||
|
import { ServerAddressSetting } from '@/features/settings/components/ServerAddressSetting.tsx';
|
||||||
|
|
||||||
|
export const SplashScreen = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
minWidth: '100vw',
|
||||||
|
minHeight: '100vh',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: 'primary.light',
|
||||||
|
...theme.applyStyles('dark', {
|
||||||
|
backgroundColor: 'primary.dark',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SuwayomiLogo
|
||||||
|
sx={{
|
||||||
|
fontSize: 250,
|
||||||
|
[theme.breakpoints.up('lg')]: {
|
||||||
|
fontSize: 350,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
circleRingColor={theme.palette.primary.light}
|
||||||
|
/>
|
||||||
|
{import.meta.env.DEV && (
|
||||||
|
<Stack sx={{ height: 'auto', mt: 5 }}>
|
||||||
|
<ServerAddressSetting />
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
143
src/features/authentication/screens/LoginPage.tsx
Normal file
143
src/features/authentication/screens/LoginPage.tsx
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 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 { useEffect, useState } from 'react';
|
||||||
|
import TextField from '@mui/material/TextField';
|
||||||
|
import Stack from '@mui/material/Stack';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import { Navigate, useNavigate } from 'react-router-dom';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import { StringParam, useQueryParam } from 'use-query-params';
|
||||||
|
import { PasswordTextField } from '@/base/components/inputs/PasswordTextField.tsx';
|
||||||
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
import { makeToast } from '@/base/utils/Toast.ts';
|
||||||
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
import { SuwayomiLogo } from '@/assets/SuwayomiLogo.tsx';
|
||||||
|
import { useSessionContext } from '@/features/authentication/SessionContext.tsx';
|
||||||
|
import { AppRoutes } from '@/base/AppRoute.constants.ts';
|
||||||
|
import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx';
|
||||||
|
import { SearchParam } from '@/base/Base.types.ts';
|
||||||
|
import { ServerAddressSetting } from '@/features/settings/components/ServerAddressSetting.tsx';
|
||||||
|
|
||||||
|
export const LoginPage = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { setOverride } = useNavBarContext();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { isAuthRequired, accessToken, refreshToken } = useSessionContext();
|
||||||
|
|
||||||
|
const [redirect] = useQueryParam(SearchParam.REDIRECT, StringParam);
|
||||||
|
const [loginUser, { loading: isLoading }] = requestManager.useLoginUser();
|
||||||
|
|
||||||
|
const [username, setUsername] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
|
||||||
|
const isAuthenticated = !isAuthRequired || (!!isAuthRequired && !!accessToken && !!refreshToken);
|
||||||
|
|
||||||
|
const doLogin = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await loginUser({ variables: { username, password } });
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
AuthManager.setTokens(data.login.accessToken, data.login.refreshToken);
|
||||||
|
navigate(redirect ?? AppRoutes.root.path);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
makeToast(t('tracking.action.login.label.failure', { name: 'Suwayomi' }), 'error', getErrorMessage(e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setOverride({ status: true, value: null });
|
||||||
|
|
||||||
|
return () => setOverride({ status: false, value: null });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (isAuthenticated) {
|
||||||
|
return <Navigate to={AppRoutes.root.path} replace />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
[theme.breakpoints.up('lg')]: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
minHeight: '50vh',
|
||||||
|
flexBasis: '60%',
|
||||||
|
p: 4,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: 'primary.light',
|
||||||
|
...theme.applyStyles('dark', {
|
||||||
|
backgroundColor: 'primary.dark',
|
||||||
|
}),
|
||||||
|
[theme.breakpoints.up('lg')]: {
|
||||||
|
minHeight: '0vh',
|
||||||
|
height: '100vh',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SuwayomiLogo
|
||||||
|
sx={{
|
||||||
|
fontSize: 250,
|
||||||
|
[theme.breakpoints.up('lg')]: {
|
||||||
|
fontSize: 350,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
circleRingColor={theme.palette.primary.light}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
minHeight: '50vh',
|
||||||
|
flexBasis: '40%',
|
||||||
|
p: 4,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
[theme.breakpoints.up('lg')]: {
|
||||||
|
minHeight: '0vh',
|
||||||
|
height: '100vh',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack sx={{ maxWidth: 300, gap: 2 }}>
|
||||||
|
<Stack>
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
margin="dense"
|
||||||
|
id="username"
|
||||||
|
name="username"
|
||||||
|
label={t('global.label.username')}
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
variant="standard"
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
<PasswordTextField
|
||||||
|
margin="dense"
|
||||||
|
fullWidth
|
||||||
|
variant="standard"
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
{import.meta.env.DEV && <ServerAddressSetting />}
|
||||||
|
</Stack>
|
||||||
|
<Button disabled={isLoading || (!username && !password)} variant="contained" onClick={doLogin}>
|
||||||
|
{t('global.button.log_in')}
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import dayjs from 'dayjs';
|
||||||
import { DEFAULT_DEVICE } from '@/features/device/services/Device.ts';
|
import { DEFAULT_DEVICE } from '@/features/device/services/Device.ts';
|
||||||
import { DEFAULT_SORT_SETTINGS } from '@/features/migration/Migration.constants.ts';
|
import { DEFAULT_SORT_SETTINGS } from '@/features/migration/Migration.constants.ts';
|
||||||
import { GlobalUpdateSkipEntriesSettings, MetadataServerSettings } from '@/features/settings/Settings.types.ts';
|
import { GlobalUpdateSkipEntriesSettings, MetadataServerSettings } from '@/features/settings/Settings.types.ts';
|
||||||
@@ -90,9 +91,13 @@ const AUTH_MODES_TO_TRANSLATION_KEY: { [mode in AuthMode]: SelectSettingValueDis
|
|||||||
description: 'settings.server.auth.mode.option.basicAuth.label.description',
|
description: 'settings.server.auth.mode.option.basicAuth.label.description',
|
||||||
},
|
},
|
||||||
[AuthMode.SimpleLogin]: {
|
[AuthMode.SimpleLogin]: {
|
||||||
text: 'settings.server.auth.mode.option.simpleLogin.label.title',
|
text: 'settings.server.auth.mode.option.simple_login.label.title',
|
||||||
description: 'settings.server.auth.mode.option.simpleLogin.label.description',
|
description: 'settings.server.auth.mode.option.simple_login.label.description',
|
||||||
disclaimer: 'settings.server.auth.mode.option.simpleLogin.label.info',
|
disclaimer: 'settings.server.auth.mode.option.simple_login.label.info',
|
||||||
|
},
|
||||||
|
[AuthMode.UiLogin]: {
|
||||||
|
text: 'settings.server.auth.mode.option.ui_login.label.title',
|
||||||
|
description: 'settings.server.auth.mode.option.ui_login.label.description',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export const AUTH_MODES_SELECT_VALUES: SelectSettingValue<AuthMode>[] = AUTH_MODES.map((mode) => [
|
export const AUTH_MODES_SELECT_VALUES: SelectSettingValue<AuthMode>[] = AUTH_MODES.map((mode) => [
|
||||||
@@ -183,3 +188,15 @@ export const WEB_UI_UPDATE_INTERVAL = {
|
|||||||
min: 1,
|
min: 1,
|
||||||
max: 23,
|
max: 23,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const JWT_ACCESS_TOKEN_EXPIRY = {
|
||||||
|
default: dayjs.duration(5, 'minute').asMinutes(),
|
||||||
|
min: dayjs.duration(1, 'minute').asMinutes(),
|
||||||
|
max: dayjs.duration(4, 'hour').asMinutes(),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const JWT_REFRESH_TOKEN_EXPIRY = {
|
||||||
|
default: dayjs.duration(60, 'day').asDays(),
|
||||||
|
min: dayjs.duration(1, 'day').asDays(),
|
||||||
|
max: dayjs.duration(1, 'year').asDays(),
|
||||||
|
};
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ export type ServerSettingsType = Pick<
|
|||||||
| 'authMode'
|
| 'authMode'
|
||||||
| 'authUsername'
|
| 'authUsername'
|
||||||
| 'authPassword'
|
| 'authPassword'
|
||||||
|
| 'jwtAudience'
|
||||||
|
| 'jwtTokenExpiry'
|
||||||
|
| 'jwtRefreshExpiry'
|
||||||
| 'flareSolverrEnabled'
|
| 'flareSolverrEnabled'
|
||||||
| 'flareSolverrTimeout'
|
| 'flareSolverrTimeout'
|
||||||
| 'flareSolverrUrl'
|
| 'flareSolverrUrl'
|
||||||
|
|||||||
33
src/features/settings/components/ServerAddressSetting.tsx
Normal file
33
src/features/settings/components/ServerAddressSetting.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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 { TextSetting } from '@/base/components/settings/text/TextSetting.tsx';
|
||||||
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
import { useLocalStorage } from '@/base/hooks/useStorage.tsx';
|
||||||
|
|
||||||
|
export const ServerAddressSetting = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [serverAddress, setServerAddress] = useLocalStorage<string>('serverBaseURL', window.location.origin);
|
||||||
|
|
||||||
|
const handleServerAddressChange = (address: string) => {
|
||||||
|
const serverBaseUrl = address.replaceAll(/(\/)+$/g, '');
|
||||||
|
setServerAddress(serverBaseUrl);
|
||||||
|
requestManager.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextSetting
|
||||||
|
settingName={t('settings.about.server.label.address')}
|
||||||
|
handleChange={handleServerAddressChange}
|
||||||
|
value={serverAddress}
|
||||||
|
placeholder="http://localhost:4567"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -15,8 +15,8 @@ import ListItemText from '@mui/material/ListItemText';
|
|||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import ListSubheader from '@mui/material/ListSubheader';
|
import ListSubheader from '@mui/material/ListSubheader';
|
||||||
import { t as translate } from 'i18next';
|
import { t as translate } from 'i18next';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { useLocalStorage } from '@/base/hooks/useStorage.tsx';
|
|
||||||
import { TextSetting } from '@/base/components/settings/text/TextSetting.tsx';
|
import { TextSetting } from '@/base/components/settings/text/TextSetting.tsx';
|
||||||
import { NumberSetting } from '@/base/components/settings/NumberSetting.tsx';
|
import { NumberSetting } from '@/base/components/settings/NumberSetting.tsx';
|
||||||
import { SelectSetting } from '@/base/components/settings/SelectSetting.tsx';
|
import { SelectSetting } from '@/base/components/settings/SelectSetting.tsx';
|
||||||
@@ -33,7 +33,13 @@ import { ServerSettings as GqlServerSettings, ServerSettingsType } from '@/featu
|
|||||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||||
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
|
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
|
||||||
import { AuthMode, SortOrder } from '@/lib/graphql/generated/graphql';
|
import { AuthMode, SortOrder } from '@/lib/graphql/generated/graphql';
|
||||||
import { AUTH_MODES_SELECT_VALUES } from '@/features/settings/Settings.constants.ts';
|
import {
|
||||||
|
AUTH_MODES_SELECT_VALUES,
|
||||||
|
JWT_ACCESS_TOKEN_EXPIRY,
|
||||||
|
JWT_REFRESH_TOKEN_EXPIRY,
|
||||||
|
} from '@/features/settings/Settings.constants.ts';
|
||||||
|
import { ServerAddressSetting } from '@/features/settings/components/ServerAddressSetting.tsx';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
|
||||||
const extractServerSettings = (settings: GqlServerSettings): ServerSettingsType => ({
|
const extractServerSettings = (settings: GqlServerSettings): ServerSettingsType => ({
|
||||||
ip: settings.ip,
|
ip: settings.ip,
|
||||||
@@ -52,6 +58,9 @@ const extractServerSettings = (settings: GqlServerSettings): ServerSettingsType
|
|||||||
authMode: settings.authMode,
|
authMode: settings.authMode,
|
||||||
authUsername: settings.authUsername,
|
authUsername: settings.authUsername,
|
||||||
authPassword: settings.authPassword,
|
authPassword: settings.authPassword,
|
||||||
|
jwtAudience: settings.jwtAudience,
|
||||||
|
jwtTokenExpiry: settings.jwtTokenExpiry,
|
||||||
|
jwtRefreshExpiry: settings.jwtRefreshExpiry,
|
||||||
flareSolverrEnabled: settings.flareSolverrEnabled,
|
flareSolverrEnabled: settings.flareSolverrEnabled,
|
||||||
flareSolverrTimeout: settings.flareSolverrTimeout,
|
flareSolverrTimeout: settings.flareSolverrTimeout,
|
||||||
flareSolverrUrl: settings.flareSolverrUrl,
|
flareSolverrUrl: settings.flareSolverrUrl,
|
||||||
@@ -99,24 +108,18 @@ export const ServerSettings = () => {
|
|||||||
});
|
});
|
||||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
|
|
||||||
const [serverAddress, setServerAddress] = useLocalStorage<string>(
|
const updateSetting = async <Setting extends keyof ServerSettingsType>(
|
||||||
'serverBaseURL',
|
|
||||||
import.meta.env.VITE_SERVER_URL_DEFAULT,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleServerAddressChange = (address: string) => {
|
|
||||||
const serverBaseUrl = address.replaceAll(/(\/)+$/g, '');
|
|
||||||
setServerAddress(serverBaseUrl);
|
|
||||||
requestManager.reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSetting = <Setting extends keyof ServerSettingsType>(
|
|
||||||
setting: Setting,
|
setting: Setting,
|
||||||
value: ServerSettingsType[Setting],
|
value: ServerSettingsType[Setting],
|
||||||
|
onCompletion?: (success: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch((e) =>
|
try {
|
||||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
await mutateSettings({ variables: { input: { settings: { [setting]: value } } } });
|
||||||
);
|
onCompletion?.(true);
|
||||||
|
} catch (e) {
|
||||||
|
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e));
|
||||||
|
onCompletion?.(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const localSettings = useMemo(
|
const localSettings = useMemo(
|
||||||
@@ -128,12 +131,7 @@ export const ServerSettings = () => {
|
|||||||
</ListSubheader>
|
</ListSubheader>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<TextSetting
|
<ServerAddressSetting />
|
||||||
settingName={t('settings.about.server.label.address')}
|
|
||||||
handleChange={handleServerAddressChange}
|
|
||||||
value={serverAddress}
|
|
||||||
placeholder="http://localhost:4567"
|
|
||||||
/>
|
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={t('global.update.settings.inform.label.title')}
|
primary={t('global.update.settings.inform.label.title')}
|
||||||
@@ -147,7 +145,7 @@ export const ServerSettings = () => {
|
|||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
),
|
),
|
||||||
[serverAddress, serverInformAvailableUpdate],
|
[serverInformAvailableUpdate],
|
||||||
);
|
);
|
||||||
|
|
||||||
const loading = areMetadataServerSettingsLoading || areServerSettingsLoading;
|
const loading = areMetadataServerSettingsLoading || areServerSettingsLoading;
|
||||||
@@ -187,8 +185,8 @@ export const ServerSettings = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const serverSettings = extractServerSettings(data!.settings);
|
const serverSettings = extractServerSettings(data!.settings);
|
||||||
const authModeDisabled = !serverSettings.authUsername.trim() || !serverSettings.authPassword.trim();
|
const authModeDisabled = !serverSettings.authUsername?.trim() || !serverSettings.authPassword?.trim();
|
||||||
|
console.log('asdf', serverSettings.jwtTokenExpiry, serverSettings.jwtRefreshExpiry);
|
||||||
return (
|
return (
|
||||||
<List sx={{ pt: 0 }}>
|
<List sx={{ pt: 0 }}>
|
||||||
{localSettings}
|
{localSettings}
|
||||||
@@ -271,7 +269,19 @@ export const ServerSettings = () => {
|
|||||||
settingName={t('settings.server.auth.label.title')}
|
settingName={t('settings.server.auth.label.title')}
|
||||||
value={serverSettings.authMode}
|
value={serverSettings.authMode}
|
||||||
values={AUTH_MODES_SELECT_VALUES}
|
values={AUTH_MODES_SELECT_VALUES}
|
||||||
handleChange={(mode) => updateSetting('authMode', mode)}
|
handleChange={(mode) => {
|
||||||
|
updateSetting('authMode', mode, (success) => {
|
||||||
|
if (!success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode !== AuthMode.UiLogin) {
|
||||||
|
AuthManager.removeTokens();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthManager.setAuthRequired(mode === AuthMode.UiLogin);
|
||||||
|
});
|
||||||
|
}}
|
||||||
disabled={authModeDisabled}
|
disabled={authModeDisabled}
|
||||||
/>
|
/>
|
||||||
<TextSetting
|
<TextSetting
|
||||||
@@ -287,6 +297,41 @@ export const ServerSettings = () => {
|
|||||||
validate={(value) => serverSettings.authMode === AuthMode.None || !!value.trim()}
|
validate={(value) => serverSettings.authMode === AuthMode.None || !!value.trim()}
|
||||||
handleChange={(authPassword) => updateSetting('authPassword', authPassword)}
|
handleChange={(authPassword) => updateSetting('authPassword', authPassword)}
|
||||||
/>
|
/>
|
||||||
|
{serverSettings.authMode === AuthMode.UiLogin && (
|
||||||
|
<>
|
||||||
|
<TextSetting
|
||||||
|
settingName={t('settings.server.auth.jwt.audience')}
|
||||||
|
value={serverSettings.jwtAudience}
|
||||||
|
handleChange={(audience) => updateSetting('jwtAudience', audience)}
|
||||||
|
/>
|
||||||
|
<NumberSetting
|
||||||
|
settingTitle={t('settings.server.auth.jwt.access_token_expiry')}
|
||||||
|
settingValue={dayjs.duration(serverSettings.jwtTokenExpiry).humanize()}
|
||||||
|
value={dayjs.duration(serverSettings.jwtTokenExpiry).asMinutes()}
|
||||||
|
valueUnit={t('global.time.minutes.minute_other')}
|
||||||
|
defaultValue={JWT_ACCESS_TOKEN_EXPIRY.default}
|
||||||
|
minValue={JWT_ACCESS_TOKEN_EXPIRY.min}
|
||||||
|
maxValue={JWT_ACCESS_TOKEN_EXPIRY.max}
|
||||||
|
handleUpdate={(expiry) =>
|
||||||
|
updateSetting('jwtTokenExpiry', dayjs.duration(expiry, 'minute').toISOString())
|
||||||
|
}
|
||||||
|
showSlider
|
||||||
|
/>
|
||||||
|
<NumberSetting
|
||||||
|
settingTitle={t('settings.server.auth.jwt.refresh_token_expiry')}
|
||||||
|
settingValue={dayjs.duration(serverSettings.jwtRefreshExpiry).humanize()}
|
||||||
|
value={dayjs.duration(serverSettings.jwtRefreshExpiry).asDays()}
|
||||||
|
valueUnit={t('global.time.days.day_other')}
|
||||||
|
defaultValue={JWT_REFRESH_TOKEN_EXPIRY.default}
|
||||||
|
minValue={JWT_REFRESH_TOKEN_EXPIRY.min}
|
||||||
|
maxValue={JWT_REFRESH_TOKEN_EXPIRY.max}
|
||||||
|
handleUpdate={(expiry) =>
|
||||||
|
updateSetting('jwtRefreshExpiry', dayjs.duration(expiry, 'day').toISOString())
|
||||||
|
}
|
||||||
|
showSlider
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</List>
|
</List>
|
||||||
<List
|
<List
|
||||||
subheader={
|
subheader={
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import ListItemButton from '@mui/material/ListItemButton';
|
|||||||
import Chip from '@mui/material/Chip';
|
import Chip from '@mui/material/Chip';
|
||||||
import ListItemAvatar from '@mui/material/ListItemAvatar';
|
import ListItemAvatar from '@mui/material/ListItemAvatar';
|
||||||
import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction';
|
import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction';
|
||||||
import Avatar from '@mui/material/Avatar';
|
|
||||||
import ListItemText from '@mui/material/ListItemText';
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import Dialog from '@mui/material/Dialog';
|
import Dialog from '@mui/material/Dialog';
|
||||||
import DialogTitle from '@mui/material/DialogTitle';
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
@@ -28,6 +27,7 @@ import { Trackers } from '@/features/tracker/services/Trackers.ts';
|
|||||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||||
import { useLocalStorage } from '@/base/hooks/useStorage.tsx';
|
import { useLocalStorage } from '@/base/hooks/useStorage.tsx';
|
||||||
import { TTrackerSearch } from '@/features/tracker/Tracker.types.ts';
|
import { TTrackerSearch } from '@/features/tracker/Tracker.types.ts';
|
||||||
|
import { AvatarSpinner } from '@/base/components/AvatarSpinner.tsx';
|
||||||
|
|
||||||
export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) => {
|
export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -86,11 +86,15 @@ export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) =>
|
|||||||
<>
|
<>
|
||||||
<ListItemButton {...bindTrigger(popupState)} onClick={() => onClick(popupState.open)}>
|
<ListItemButton {...bindTrigger(popupState)} onClick={() => onClick(popupState.open)}>
|
||||||
<ListItemAvatar sx={{ paddingRight: '20px' }}>
|
<ListItemAvatar sx={{ paddingRight: '20px' }}>
|
||||||
<Avatar
|
<AvatarSpinner
|
||||||
alt={`${tracker.name}`}
|
alt={`${tracker.name}`}
|
||||||
src={requestManager.getValidImgUrlFor(tracker.icon)}
|
iconUrl={requestManager.getValidImgUrlFor(tracker.icon)}
|
||||||
variant="rounded"
|
slots={{
|
||||||
sx={{ width: 64, height: 64 }}
|
avatarProps: {
|
||||||
|
variant: 'rounded',
|
||||||
|
sx: { width: 64, height: 64 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText primary={tracker.name} />
|
<ListItemText primary={tracker.name} />
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import Card from '@mui/material/Card';
|
import Card from '@mui/material/Card';
|
||||||
import CardContent from '@mui/material/CardContent';
|
import CardContent from '@mui/material/CardContent';
|
||||||
import Avatar from '@mui/material/Avatar';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
@@ -44,6 +43,7 @@ import { CheckboxInput } from '@/base/components/inputs/CheckboxInput.tsx';
|
|||||||
import { TrackRecordType } from '@/lib/graphql/generated/graphql.ts';
|
import { TrackRecordType } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||||
import { TTrackerBind, TTrackRecordBind } from '@/features/tracker/Tracker.types.ts';
|
import { TTrackerBind, TTrackRecordBind } from '@/features/tracker/Tracker.types.ts';
|
||||||
|
import { AvatarSpinner } from '@/base/components/AvatarSpinner.tsx';
|
||||||
|
|
||||||
const TrackerActiveLink = ({ children, url }: { children: React.ReactNode; url: string }) => (
|
const TrackerActiveLink = ({ children, url }: { children: React.ReactNode; url: string }) => (
|
||||||
<Link href={url} rel="noreferrer" target="_blank" underline="none" color="inherit">
|
<Link href={url} rel="noreferrer" target="_blank" underline="none" color="inherit">
|
||||||
@@ -203,11 +203,15 @@ const TrackerActiveHeader = ({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<TrackerActiveLink url={trackRecord.remoteUrl}>
|
<TrackerActiveLink url={trackRecord.remoteUrl}>
|
||||||
<Avatar
|
<AvatarSpinner
|
||||||
alt={`${tracker.name}`}
|
alt={`${tracker.name}`}
|
||||||
src={requestManager.getValidImgUrlFor(tracker.icon)}
|
iconUrl={requestManager.getValidImgUrlFor(tracker.icon)}
|
||||||
variant="rounded"
|
slots={{
|
||||||
sx={{ width: 64, height: 64 }}
|
avatarProps: {
|
||||||
|
variant: 'rounded',
|
||||||
|
sx: { width: 64, height: 64 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</TrackerActiveLink>
|
</TrackerActiveLink>
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import Card from '@mui/material/Card';
|
import Card from '@mui/material/Card';
|
||||||
import CardContent from '@mui/material/CardContent';
|
import CardContent from '@mui/material/CardContent';
|
||||||
import Avatar from '@mui/material/Avatar';
|
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Stack from '@mui/material/Stack';
|
import Stack from '@mui/material/Stack';
|
||||||
@@ -16,6 +15,7 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
|
|||||||
import { CARD_STYLING } from '@/features/tracker/Tracker.constants.ts';
|
import { CARD_STYLING } from '@/features/tracker/Tracker.constants.ts';
|
||||||
|
|
||||||
import { TTrackerBase } from '@/features/tracker/Tracker.types.ts';
|
import { TTrackerBase } from '@/features/tracker/Tracker.types.ts';
|
||||||
|
import { AvatarSpinner } from '@/base/components/AvatarSpinner.tsx';
|
||||||
|
|
||||||
export const TrackerUntrackedCard = ({
|
export const TrackerUntrackedCard = ({
|
||||||
tracker,
|
tracker,
|
||||||
@@ -35,11 +35,15 @@ export const TrackerUntrackedCard = ({
|
|||||||
gap: 3,
|
gap: 3,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Avatar
|
<AvatarSpinner
|
||||||
alt={`${tracker.name}`}
|
alt={`${tracker.name}`}
|
||||||
src={requestManager.getValidImgUrlFor(tracker.icon)}
|
iconUrl={requestManager.getValidImgUrlFor(tracker.icon)}
|
||||||
variant="rounded"
|
slots={{
|
||||||
sx={{ width: 64, height: 64 }}
|
avatarProps: {
|
||||||
|
variant: 'rounded',
|
||||||
|
sx: { width: 64, height: 64 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Button sx={{ flexGrow: '1' }} onClick={onClick}>
|
<Button sx={{ flexGrow: '1' }} onClick={onClick}>
|
||||||
{t('tracking.action.button.add_tracking')}
|
{t('tracking.action.button.add_tracking')}
|
||||||
|
|||||||
@@ -7,14 +7,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import '@/polyfill.manual';
|
import '@/polyfill.manual';
|
||||||
|
import '@fontsource/roboto';
|
||||||
|
import '@/lib/dayjs/Setup.ts';
|
||||||
|
import '@/index.css';
|
||||||
import { StrictMode } from 'react';
|
import { StrictMode } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { App } from '@/App';
|
import { App } from '@/App';
|
||||||
import '@/index.css';
|
|
||||||
// roboto font
|
|
||||||
import '@fontsource/roboto';
|
|
||||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||||
import '@/lib/dayjs/Setup.ts';
|
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.ready.then((registration) => {
|
navigator.serviceWorker.ready.then((registration) => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import calendar from 'dayjs/plugin/calendar';
|
|||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
import isToday from 'dayjs/plugin/isToday';
|
import isToday from 'dayjs/plugin/isToday';
|
||||||
import isYesterday from 'dayjs/plugin/isYesterday';
|
import isYesterday from 'dayjs/plugin/isYesterday';
|
||||||
|
import duration from 'dayjs/plugin/duration';
|
||||||
import { importDayJsLocale } from '@/lib/dayjs/LocaleImporter.ts';
|
import { importDayJsLocale } from '@/lib/dayjs/LocaleImporter.ts';
|
||||||
// import localizedFormat from 'dayjs/plugin/localizedFormat';
|
// import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||||
// import updateLocale from 'dayjs/plugin/updateLocale';
|
// import updateLocale from 'dayjs/plugin/updateLocale';
|
||||||
@@ -22,6 +23,7 @@ dayjs.extend(calendar);
|
|||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
dayjs.extend(isToday);
|
dayjs.extend(isToday);
|
||||||
dayjs.extend(isYesterday);
|
dayjs.extend(isYesterday);
|
||||||
|
dayjs.extend(duration);
|
||||||
// dayjs.extend(localizedFormat);
|
// dayjs.extend(localizedFormat);
|
||||||
// dayjs.extend(updateLocale);
|
// dayjs.extend(updateLocale);
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ export const SERVER_SETTINGS = gql`
|
|||||||
authMode
|
authMode
|
||||||
authPassword
|
authPassword
|
||||||
authUsername
|
authUsername
|
||||||
|
jwtAudience
|
||||||
|
jwtTokenExpiry
|
||||||
|
jwtRefreshExpiry
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
debugLogsEnabled
|
debugLogsEnabled
|
||||||
|
|||||||
@@ -110,10 +110,11 @@ export type CheckBoxFilterFieldPolicy = {
|
|||||||
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
name?: FieldPolicy<any> | FieldReadFunction<any>
|
name?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type CheckBoxPreferenceKeySpecifier = ('currentValue' | 'default' | 'key' | 'summary' | 'title' | 'visible' | CheckBoxPreferenceKeySpecifier)[];
|
export type CheckBoxPreferenceKeySpecifier = ('currentValue' | 'default' | 'enabled' | 'key' | 'summary' | 'title' | 'visible' | CheckBoxPreferenceKeySpecifier)[];
|
||||||
export type CheckBoxPreferenceFieldPolicy = {
|
export type CheckBoxPreferenceFieldPolicy = {
|
||||||
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
enabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
summary?: FieldPolicy<any> | FieldReadFunction<any>,
|
summary?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -245,12 +246,13 @@ export type EdgeFieldPolicy = {
|
|||||||
cursor?: FieldPolicy<any> | FieldReadFunction<any>,
|
cursor?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
node?: FieldPolicy<any> | FieldReadFunction<any>
|
node?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type EditTextPreferenceKeySpecifier = ('currentValue' | 'default' | 'dialogMessage' | 'dialogTitle' | 'key' | 'summary' | 'text' | 'title' | 'visible' | EditTextPreferenceKeySpecifier)[];
|
export type EditTextPreferenceKeySpecifier = ('currentValue' | 'default' | 'dialogMessage' | 'dialogTitle' | 'enabled' | 'key' | 'summary' | 'text' | 'title' | 'visible' | EditTextPreferenceKeySpecifier)[];
|
||||||
export type EditTextPreferenceFieldPolicy = {
|
export type EditTextPreferenceFieldPolicy = {
|
||||||
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
dialogMessage?: FieldPolicy<any> | FieldReadFunction<any>,
|
dialogMessage?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
dialogTitle?: FieldPolicy<any> | FieldReadFunction<any>,
|
dialogTitle?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
enabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
summary?: FieldPolicy<any> | FieldReadFunction<any>,
|
summary?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
text?: FieldPolicy<any> | FieldReadFunction<any>,
|
text?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -295,11 +297,12 @@ export type ExtensionTypeFieldPolicy = {
|
|||||||
versionCode?: FieldPolicy<any> | FieldReadFunction<any>,
|
versionCode?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
versionName?: FieldPolicy<any> | FieldReadFunction<any>
|
versionName?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type FetchChapterPagesPayloadKeySpecifier = ('chapter' | 'clientMutationId' | 'pages' | FetchChapterPagesPayloadKeySpecifier)[];
|
export type FetchChapterPagesPayloadKeySpecifier = ('chapter' | 'clientMutationId' | 'pages' | 'syncConflict' | FetchChapterPagesPayloadKeySpecifier)[];
|
||||||
export type FetchChapterPagesPayloadFieldPolicy = {
|
export type FetchChapterPagesPayloadFieldPolicy = {
|
||||||
chapter?: FieldPolicy<any> | FieldReadFunction<any>,
|
chapter?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
pages?: FieldPolicy<any> | FieldReadFunction<any>
|
pages?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
syncConflict?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type FetchChaptersPayloadKeySpecifier = ('chapters' | 'clientMutationId' | FetchChaptersPayloadKeySpecifier)[];
|
export type FetchChaptersPayloadKeySpecifier = ('chapters' | 'clientMutationId' | FetchChaptersPayloadKeySpecifier)[];
|
||||||
export type FetchChaptersPayloadFieldPolicy = {
|
export type FetchChaptersPayloadFieldPolicy = {
|
||||||
@@ -353,6 +356,19 @@ export type InstallExternalExtensionPayloadFieldPolicy = {
|
|||||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
extension?: FieldPolicy<any> | FieldReadFunction<any>
|
extension?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
|
export type KoSyncConnectPayloadKeySpecifier = ('clientMutationId' | 'message' | 'settings' | 'success' | 'username' | KoSyncConnectPayloadKeySpecifier)[];
|
||||||
|
export type KoSyncConnectPayloadFieldPolicy = {
|
||||||
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
message?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
settings?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
success?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
username?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
|
};
|
||||||
|
export type KoSyncStatusPayloadKeySpecifier = ('isLoggedIn' | 'username' | KoSyncStatusPayloadKeySpecifier)[];
|
||||||
|
export type KoSyncStatusPayloadFieldPolicy = {
|
||||||
|
isLoggedIn?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
username?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
|
};
|
||||||
export type LastUpdateTimestampPayloadKeySpecifier = ('timestamp' | LastUpdateTimestampPayloadKeySpecifier)[];
|
export type LastUpdateTimestampPayloadKeySpecifier = ('timestamp' | LastUpdateTimestampPayloadKeySpecifier)[];
|
||||||
export type LastUpdateTimestampPayloadFieldPolicy = {
|
export type LastUpdateTimestampPayloadFieldPolicy = {
|
||||||
timestamp?: FieldPolicy<any> | FieldReadFunction<any>
|
timestamp?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
@@ -363,10 +379,11 @@ export type LibraryUpdateStatusFieldPolicy = {
|
|||||||
jobsInfo?: FieldPolicy<any> | FieldReadFunction<any>,
|
jobsInfo?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
mangaUpdates?: FieldPolicy<any> | FieldReadFunction<any>
|
mangaUpdates?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type ListPreferenceKeySpecifier = ('currentValue' | 'default' | 'entries' | 'entryValues' | 'key' | 'summary' | 'title' | 'visible' | ListPreferenceKeySpecifier)[];
|
export type ListPreferenceKeySpecifier = ('currentValue' | 'default' | 'enabled' | 'entries' | 'entryValues' | 'key' | 'summary' | 'title' | 'visible' | ListPreferenceKeySpecifier)[];
|
||||||
export type ListPreferenceFieldPolicy = {
|
export type ListPreferenceFieldPolicy = {
|
||||||
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
enabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
entries?: FieldPolicy<any> | FieldReadFunction<any>,
|
entries?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
entryValues?: FieldPolicy<any> | FieldReadFunction<any>,
|
entryValues?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -374,6 +391,12 @@ export type ListPreferenceFieldPolicy = {
|
|||||||
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
visible?: FieldPolicy<any> | FieldReadFunction<any>
|
visible?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
|
export type LoginPayloadKeySpecifier = ('accessToken' | 'clientMutationId' | 'refreshToken' | LoginPayloadKeySpecifier)[];
|
||||||
|
export type LoginPayloadFieldPolicy = {
|
||||||
|
accessToken?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
refreshToken?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
|
};
|
||||||
export type LoginTrackerCredentialsPayloadKeySpecifier = ('clientMutationId' | 'isLoggedIn' | 'tracker' | LoginTrackerCredentialsPayloadKeySpecifier)[];
|
export type LoginTrackerCredentialsPayloadKeySpecifier = ('clientMutationId' | 'isLoggedIn' | 'tracker' | LoginTrackerCredentialsPayloadKeySpecifier)[];
|
||||||
export type LoginTrackerCredentialsPayloadFieldPolicy = {
|
export type LoginTrackerCredentialsPayloadFieldPolicy = {
|
||||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -386,6 +409,12 @@ export type LoginTrackerOAuthPayloadFieldPolicy = {
|
|||||||
isLoggedIn?: FieldPolicy<any> | FieldReadFunction<any>,
|
isLoggedIn?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
tracker?: FieldPolicy<any> | FieldReadFunction<any>
|
tracker?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
|
export type LogoutKoSyncAccountPayloadKeySpecifier = ('clientMutationId' | 'settings' | 'success' | LogoutKoSyncAccountPayloadKeySpecifier)[];
|
||||||
|
export type LogoutKoSyncAccountPayloadFieldPolicy = {
|
||||||
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
settings?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
success?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
|
};
|
||||||
export type LogoutTrackerPayloadKeySpecifier = ('clientMutationId' | 'isLoggedIn' | 'tracker' | LogoutTrackerPayloadKeySpecifier)[];
|
export type LogoutTrackerPayloadKeySpecifier = ('clientMutationId' | 'isLoggedIn' | 'tracker' | LogoutTrackerPayloadKeySpecifier)[];
|
||||||
export type LogoutTrackerPayloadFieldPolicy = {
|
export type LogoutTrackerPayloadFieldPolicy = {
|
||||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -464,12 +493,13 @@ export type MetaTypeFieldPolicy = {
|
|||||||
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
value?: FieldPolicy<any> | FieldReadFunction<any>
|
value?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type MultiSelectListPreferenceKeySpecifier = ('currentValue' | 'default' | 'dialogMessage' | 'dialogTitle' | 'entries' | 'entryValues' | 'key' | 'summary' | 'title' | 'visible' | MultiSelectListPreferenceKeySpecifier)[];
|
export type MultiSelectListPreferenceKeySpecifier = ('currentValue' | 'default' | 'dialogMessage' | 'dialogTitle' | 'enabled' | 'entries' | 'entryValues' | 'key' | 'summary' | 'title' | 'visible' | MultiSelectListPreferenceKeySpecifier)[];
|
||||||
export type MultiSelectListPreferenceFieldPolicy = {
|
export type MultiSelectListPreferenceFieldPolicy = {
|
||||||
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
dialogMessage?: FieldPolicy<any> | FieldReadFunction<any>,
|
dialogMessage?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
dialogTitle?: FieldPolicy<any> | FieldReadFunction<any>,
|
dialogTitle?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
enabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
entries?: FieldPolicy<any> | FieldReadFunction<any>,
|
entries?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
entryValues?: FieldPolicy<any> | FieldReadFunction<any>,
|
entryValues?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -477,11 +507,12 @@ export type MultiSelectListPreferenceFieldPolicy = {
|
|||||||
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
visible?: FieldPolicy<any> | FieldReadFunction<any>
|
visible?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type MutationKeySpecifier = ('bindTrack' | 'clearCachedImages' | 'clearDownloader' | 'createBackup' | 'createCategory' | 'deleteCategory' | 'deleteCategoryMeta' | 'deleteChapterMeta' | 'deleteDownloadedChapter' | 'deleteDownloadedChapters' | 'deleteGlobalMeta' | 'deleteMangaMeta' | 'deleteSourceMeta' | 'dequeueChapterDownload' | 'dequeueChapterDownloads' | 'enqueueChapterDownload' | 'enqueueChapterDownloads' | 'fetchChapterPages' | 'fetchChapters' | 'fetchExtensions' | 'fetchManga' | 'fetchSourceManga' | 'fetchTrack' | 'installExternalExtension' | 'loginTrackerCredentials' | 'loginTrackerOAuth' | 'logoutTracker' | 'reorderChapterDownload' | 'resetSettings' | 'resetWebUIUpdateStatus' | 'restoreBackup' | 'setCategoryMeta' | 'setChapterMeta' | 'setGlobalMeta' | 'setMangaMeta' | 'setSettings' | 'setSourceMeta' | 'startDownloader' | 'stopDownloader' | 'trackProgress' | 'unbindTrack' | 'updateCategories' | 'updateCategory' | 'updateCategoryManga' | 'updateCategoryOrder' | 'updateChapter' | 'updateChapters' | 'updateExtension' | 'updateExtensions' | 'updateLibrary' | 'updateLibraryManga' | 'updateManga' | 'updateMangaCategories' | 'updateMangas' | 'updateMangasCategories' | 'updateSourcePreference' | 'updateStop' | 'updateTrack' | 'updateWebUI' | MutationKeySpecifier)[];
|
export type MutationKeySpecifier = ('bindTrack' | 'clearCachedImages' | 'clearDownloader' | 'connectKoSyncAccount' | 'createBackup' | 'createCategory' | 'deleteCategory' | 'deleteCategoryMeta' | 'deleteChapterMeta' | 'deleteDownloadedChapter' | 'deleteDownloadedChapters' | 'deleteGlobalMeta' | 'deleteMangaMeta' | 'deleteSourceMeta' | 'dequeueChapterDownload' | 'dequeueChapterDownloads' | 'enqueueChapterDownload' | 'enqueueChapterDownloads' | 'fetchChapterPages' | 'fetchChapters' | 'fetchExtensions' | 'fetchManga' | 'fetchSourceManga' | 'fetchTrack' | 'installExternalExtension' | 'login' | 'loginTrackerCredentials' | 'loginTrackerOAuth' | 'logoutKoSyncAccount' | 'logoutTracker' | 'refreshToken' | 'reorderChapterDownload' | 'resetSettings' | 'resetWebUIUpdateStatus' | 'restoreBackup' | 'setCategoryMeta' | 'setChapterMeta' | 'setGlobalMeta' | 'setMangaMeta' | 'setSettings' | 'setSourceMeta' | 'startDownloader' | 'stopDownloader' | 'trackProgress' | 'unbindTrack' | 'updateCategories' | 'updateCategory' | 'updateCategoryManga' | 'updateCategoryOrder' | 'updateChapter' | 'updateChapters' | 'updateExtension' | 'updateExtensions' | 'updateLibrary' | 'updateLibraryManga' | 'updateManga' | 'updateMangaCategories' | 'updateMangas' | 'updateMangasCategories' | 'updateSourcePreference' | 'updateStop' | 'updateTrack' | 'updateWebUI' | MutationKeySpecifier)[];
|
||||||
export type MutationFieldPolicy = {
|
export type MutationFieldPolicy = {
|
||||||
bindTrack?: FieldPolicy<any> | FieldReadFunction<any>,
|
bindTrack?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
clearCachedImages?: FieldPolicy<any> | FieldReadFunction<any>,
|
clearCachedImages?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
clearDownloader?: FieldPolicy<any> | FieldReadFunction<any>,
|
clearDownloader?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
connectKoSyncAccount?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
createBackup?: FieldPolicy<any> | FieldReadFunction<any>,
|
createBackup?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
createCategory?: FieldPolicy<any> | FieldReadFunction<any>,
|
createCategory?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
deleteCategory?: FieldPolicy<any> | FieldReadFunction<any>,
|
deleteCategory?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -503,9 +534,12 @@ export type MutationFieldPolicy = {
|
|||||||
fetchSourceManga?: FieldPolicy<any> | FieldReadFunction<any>,
|
fetchSourceManga?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
fetchTrack?: FieldPolicy<any> | FieldReadFunction<any>,
|
fetchTrack?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
installExternalExtension?: FieldPolicy<any> | FieldReadFunction<any>,
|
installExternalExtension?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
login?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
loginTrackerCredentials?: FieldPolicy<any> | FieldReadFunction<any>,
|
loginTrackerCredentials?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
loginTrackerOAuth?: FieldPolicy<any> | FieldReadFunction<any>,
|
loginTrackerOAuth?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
logoutKoSyncAccount?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
logoutTracker?: FieldPolicy<any> | FieldReadFunction<any>,
|
logoutTracker?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
refreshToken?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
reorderChapterDownload?: FieldPolicy<any> | FieldReadFunction<any>,
|
reorderChapterDownload?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
resetSettings?: FieldPolicy<any> | FieldReadFunction<any>,
|
resetSettings?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
resetWebUIUpdateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
resetWebUIUpdateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -553,7 +587,7 @@ export type PageInfoFieldPolicy = {
|
|||||||
hasPreviousPage?: FieldPolicy<any> | FieldReadFunction<any>,
|
hasPreviousPage?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
startCursor?: FieldPolicy<any> | FieldReadFunction<any>
|
startCursor?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type PartialSettingsTypeKeySpecifier = ('authMode' | 'authPassword' | 'authUsername' | 'autoDownloadAheadLimit' | 'autoDownloadIgnoreReUploads' | 'autoDownloadNewChapters' | 'autoDownloadNewChaptersLimit' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadConversions' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeEntryWithUnreadChapters' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'extensionRepos' | 'flareSolverrAsResponseFallback' | 'flareSolverrEnabled' | 'flareSolverrSessionName' | 'flareSolverrSessionTtl' | 'flareSolverrTimeout' | 'flareSolverrUrl' | 'globalUpdateInterval' | 'gqlDebugLogsEnabled' | 'initialOpenInBrowserEnabled' | 'ip' | 'localSourcePath' | 'maxLogFileSize' | 'maxLogFiles' | 'maxLogFolderSize' | 'maxSourcesInParallel' | 'opdsChapterSortOrder' | 'opdsEnablePageReadProgress' | 'opdsItemsPerPage' | 'opdsMarkAsReadOnDownload' | 'opdsShowOnlyDownloadedChapters' | 'opdsShowOnlyUnreadChapters' | 'opdsUseBinaryFileSizes' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPassword' | 'socksProxyPort' | 'socksProxyUsername' | 'socksProxyVersion' | 'systemTrayEnabled' | 'updateMangas' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | PartialSettingsTypeKeySpecifier)[];
|
export type PartialSettingsTypeKeySpecifier = ('authMode' | 'authPassword' | 'authUsername' | 'autoDownloadAheadLimit' | 'autoDownloadIgnoreReUploads' | 'autoDownloadNewChapters' | 'autoDownloadNewChaptersLimit' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadConversions' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeEntryWithUnreadChapters' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'extensionRepos' | 'flareSolverrAsResponseFallback' | 'flareSolverrEnabled' | 'flareSolverrSessionName' | 'flareSolverrSessionTtl' | 'flareSolverrTimeout' | 'flareSolverrUrl' | 'globalUpdateInterval' | 'gqlDebugLogsEnabled' | 'initialOpenInBrowserEnabled' | 'ip' | 'jwtAudience' | 'jwtRefreshExpiry' | 'jwtTokenExpiry' | 'koreaderSyncChecksumMethod' | 'koreaderSyncDeviceId' | 'koreaderSyncPercentageTolerance' | 'koreaderSyncServerUrl' | 'koreaderSyncStrategy' | 'koreaderSyncUserkey' | 'koreaderSyncUsername' | 'localSourcePath' | 'maxLogFileSize' | 'maxLogFiles' | 'maxLogFolderSize' | 'maxSourcesInParallel' | 'opdsChapterSortOrder' | 'opdsEnablePageReadProgress' | 'opdsItemsPerPage' | 'opdsMarkAsReadOnDownload' | 'opdsShowOnlyDownloadedChapters' | 'opdsShowOnlyUnreadChapters' | 'opdsUseBinaryFileSizes' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPassword' | 'socksProxyPort' | 'socksProxyUsername' | 'socksProxyVersion' | 'systemTrayEnabled' | 'updateMangas' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | PartialSettingsTypeKeySpecifier)[];
|
||||||
export type PartialSettingsTypeFieldPolicy = {
|
export type PartialSettingsTypeFieldPolicy = {
|
||||||
authMode?: FieldPolicy<any> | FieldReadFunction<any>,
|
authMode?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
authPassword?: FieldPolicy<any> | FieldReadFunction<any>,
|
authPassword?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -589,6 +623,16 @@ export type PartialSettingsTypeFieldPolicy = {
|
|||||||
gqlDebugLogsEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
gqlDebugLogsEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
initialOpenInBrowserEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
initialOpenInBrowserEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
ip?: FieldPolicy<any> | FieldReadFunction<any>,
|
ip?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtAudience?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtRefreshExpiry?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtTokenExpiry?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncChecksumMethod?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncDeviceId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncPercentageTolerance?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncServerUrl?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncStrategy?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncUserkey?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncUsername?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
localSourcePath?: FieldPolicy<any> | FieldReadFunction<any>,
|
localSourcePath?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
maxLogFileSize?: FieldPolicy<any> | FieldReadFunction<any>,
|
maxLogFileSize?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
maxLogFiles?: FieldPolicy<any> | FieldReadFunction<any>,
|
maxLogFiles?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -615,7 +659,7 @@ export type PartialSettingsTypeFieldPolicy = {
|
|||||||
webUIInterface?: FieldPolicy<any> | FieldReadFunction<any>,
|
webUIInterface?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
webUIUpdateCheckInterval?: FieldPolicy<any> | FieldReadFunction<any>
|
webUIUpdateCheckInterval?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type QueryKeySpecifier = ('aboutServer' | 'aboutWebUI' | 'categories' | 'category' | 'chapter' | 'chapters' | 'checkForServerUpdates' | 'checkForWebUIUpdate' | 'downloadStatus' | 'extension' | 'extensions' | 'getWebUIUpdateStatus' | 'lastUpdateTimestamp' | 'libraryUpdateStatus' | 'manga' | 'mangas' | 'meta' | 'metas' | 'restoreStatus' | 'searchTracker' | 'settings' | 'source' | 'sources' | 'trackRecord' | 'trackRecords' | 'tracker' | 'trackers' | 'updateStatus' | 'validateBackup' | QueryKeySpecifier)[];
|
export type QueryKeySpecifier = ('aboutServer' | 'aboutWebUI' | 'categories' | 'category' | 'chapter' | 'chapters' | 'checkForServerUpdates' | 'checkForWebUIUpdate' | 'downloadStatus' | 'extension' | 'extensions' | 'getWebUIUpdateStatus' | 'koSyncStatus' | 'lastUpdateTimestamp' | 'libraryUpdateStatus' | 'manga' | 'mangas' | 'meta' | 'metas' | 'restoreStatus' | 'searchTracker' | 'settings' | 'source' | 'sources' | 'trackRecord' | 'trackRecords' | 'tracker' | 'trackers' | 'updateStatus' | 'validateBackup' | QueryKeySpecifier)[];
|
||||||
export type QueryFieldPolicy = {
|
export type QueryFieldPolicy = {
|
||||||
aboutServer?: FieldPolicy<any> | FieldReadFunction<any>,
|
aboutServer?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
aboutWebUI?: FieldPolicy<any> | FieldReadFunction<any>,
|
aboutWebUI?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -629,6 +673,7 @@ export type QueryFieldPolicy = {
|
|||||||
extension?: FieldPolicy<any> | FieldReadFunction<any>,
|
extension?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
extensions?: FieldPolicy<any> | FieldReadFunction<any>,
|
extensions?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
getWebUIUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>>,
|
getWebUIUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>>,
|
||||||
|
koSyncStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
lastUpdateTimestamp?: FieldPolicy<any> | FieldReadFunction<any>,
|
lastUpdateTimestamp?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
libraryUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>>,
|
libraryUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>>,
|
||||||
manga?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>>,
|
manga?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>>,
|
||||||
@@ -647,6 +692,11 @@ export type QueryFieldPolicy = {
|
|||||||
updateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
updateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
validateBackup?: FieldPolicy<any> | FieldReadFunction<any>
|
validateBackup?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
|
export type RefreshTokenPayloadKeySpecifier = ('accessToken' | 'clientMutationId' | RefreshTokenPayloadKeySpecifier)[];
|
||||||
|
export type RefreshTokenPayloadFieldPolicy = {
|
||||||
|
accessToken?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
|
};
|
||||||
export type ReorderChapterDownloadPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | ReorderChapterDownloadPayloadKeySpecifier)[];
|
export type ReorderChapterDownloadPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | ReorderChapterDownloadPayloadKeySpecifier)[];
|
||||||
export type ReorderChapterDownloadPayloadFieldPolicy = {
|
export type ReorderChapterDownloadPayloadFieldPolicy = {
|
||||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -707,7 +757,7 @@ export type SetSourceMetaPayloadFieldPolicy = {
|
|||||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
meta?: FieldPolicy<any> | FieldReadFunction<any>
|
meta?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type SettingsKeySpecifier = ('authMode' | 'authPassword' | 'authUsername' | 'autoDownloadAheadLimit' | 'autoDownloadIgnoreReUploads' | 'autoDownloadNewChapters' | 'autoDownloadNewChaptersLimit' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadConversions' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeEntryWithUnreadChapters' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'extensionRepos' | 'flareSolverrAsResponseFallback' | 'flareSolverrEnabled' | 'flareSolverrSessionName' | 'flareSolverrSessionTtl' | 'flareSolverrTimeout' | 'flareSolverrUrl' | 'globalUpdateInterval' | 'gqlDebugLogsEnabled' | 'initialOpenInBrowserEnabled' | 'ip' | 'localSourcePath' | 'maxLogFileSize' | 'maxLogFiles' | 'maxLogFolderSize' | 'maxSourcesInParallel' | 'opdsChapterSortOrder' | 'opdsEnablePageReadProgress' | 'opdsItemsPerPage' | 'opdsMarkAsReadOnDownload' | 'opdsShowOnlyDownloadedChapters' | 'opdsShowOnlyUnreadChapters' | 'opdsUseBinaryFileSizes' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPassword' | 'socksProxyPort' | 'socksProxyUsername' | 'socksProxyVersion' | 'systemTrayEnabled' | 'updateMangas' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | SettingsKeySpecifier)[];
|
export type SettingsKeySpecifier = ('authMode' | 'authPassword' | 'authUsername' | 'autoDownloadAheadLimit' | 'autoDownloadIgnoreReUploads' | 'autoDownloadNewChapters' | 'autoDownloadNewChaptersLimit' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadConversions' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeEntryWithUnreadChapters' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'extensionRepos' | 'flareSolverrAsResponseFallback' | 'flareSolverrEnabled' | 'flareSolverrSessionName' | 'flareSolverrSessionTtl' | 'flareSolverrTimeout' | 'flareSolverrUrl' | 'globalUpdateInterval' | 'gqlDebugLogsEnabled' | 'initialOpenInBrowserEnabled' | 'ip' | 'jwtAudience' | 'jwtRefreshExpiry' | 'jwtTokenExpiry' | 'koreaderSyncChecksumMethod' | 'koreaderSyncDeviceId' | 'koreaderSyncPercentageTolerance' | 'koreaderSyncServerUrl' | 'koreaderSyncStrategy' | 'koreaderSyncUserkey' | 'koreaderSyncUsername' | 'localSourcePath' | 'maxLogFileSize' | 'maxLogFiles' | 'maxLogFolderSize' | 'maxSourcesInParallel' | 'opdsChapterSortOrder' | 'opdsEnablePageReadProgress' | 'opdsItemsPerPage' | 'opdsMarkAsReadOnDownload' | 'opdsShowOnlyDownloadedChapters' | 'opdsShowOnlyUnreadChapters' | 'opdsUseBinaryFileSizes' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPassword' | 'socksProxyPort' | 'socksProxyUsername' | 'socksProxyVersion' | 'systemTrayEnabled' | 'updateMangas' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | SettingsKeySpecifier)[];
|
||||||
export type SettingsFieldPolicy = {
|
export type SettingsFieldPolicy = {
|
||||||
authMode?: FieldPolicy<any> | FieldReadFunction<any>,
|
authMode?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
authPassword?: FieldPolicy<any> | FieldReadFunction<any>,
|
authPassword?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -743,6 +793,16 @@ export type SettingsFieldPolicy = {
|
|||||||
gqlDebugLogsEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
gqlDebugLogsEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
initialOpenInBrowserEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
initialOpenInBrowserEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
ip?: FieldPolicy<any> | FieldReadFunction<any>,
|
ip?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtAudience?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtRefreshExpiry?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtTokenExpiry?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncChecksumMethod?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncDeviceId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncPercentageTolerance?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncServerUrl?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncStrategy?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncUserkey?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncUsername?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
localSourcePath?: FieldPolicy<any> | FieldReadFunction<any>,
|
localSourcePath?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
maxLogFileSize?: FieldPolicy<any> | FieldReadFunction<any>,
|
maxLogFileSize?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
maxLogFiles?: FieldPolicy<any> | FieldReadFunction<any>,
|
maxLogFiles?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -781,7 +841,7 @@ export type SettingsDownloadConversionTypeFieldPolicy = {
|
|||||||
mimeType?: FieldPolicy<any> | FieldReadFunction<any>,
|
mimeType?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
target?: FieldPolicy<any> | FieldReadFunction<any>
|
target?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type SettingsTypeKeySpecifier = ('authMode' | 'authPassword' | 'authUsername' | 'autoDownloadAheadLimit' | 'autoDownloadIgnoreReUploads' | 'autoDownloadNewChapters' | 'autoDownloadNewChaptersLimit' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadConversions' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeEntryWithUnreadChapters' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'extensionRepos' | 'flareSolverrAsResponseFallback' | 'flareSolverrEnabled' | 'flareSolverrSessionName' | 'flareSolverrSessionTtl' | 'flareSolverrTimeout' | 'flareSolverrUrl' | 'globalUpdateInterval' | 'gqlDebugLogsEnabled' | 'initialOpenInBrowserEnabled' | 'ip' | 'localSourcePath' | 'maxLogFileSize' | 'maxLogFiles' | 'maxLogFolderSize' | 'maxSourcesInParallel' | 'opdsChapterSortOrder' | 'opdsEnablePageReadProgress' | 'opdsItemsPerPage' | 'opdsMarkAsReadOnDownload' | 'opdsShowOnlyDownloadedChapters' | 'opdsShowOnlyUnreadChapters' | 'opdsUseBinaryFileSizes' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPassword' | 'socksProxyPort' | 'socksProxyUsername' | 'socksProxyVersion' | 'systemTrayEnabled' | 'updateMangas' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | SettingsTypeKeySpecifier)[];
|
export type SettingsTypeKeySpecifier = ('authMode' | 'authPassword' | 'authUsername' | 'autoDownloadAheadLimit' | 'autoDownloadIgnoreReUploads' | 'autoDownloadNewChapters' | 'autoDownloadNewChaptersLimit' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadConversions' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeEntryWithUnreadChapters' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'extensionRepos' | 'flareSolverrAsResponseFallback' | 'flareSolverrEnabled' | 'flareSolverrSessionName' | 'flareSolverrSessionTtl' | 'flareSolverrTimeout' | 'flareSolverrUrl' | 'globalUpdateInterval' | 'gqlDebugLogsEnabled' | 'initialOpenInBrowserEnabled' | 'ip' | 'jwtAudience' | 'jwtRefreshExpiry' | 'jwtTokenExpiry' | 'koreaderSyncChecksumMethod' | 'koreaderSyncDeviceId' | 'koreaderSyncPercentageTolerance' | 'koreaderSyncServerUrl' | 'koreaderSyncStrategy' | 'koreaderSyncUserkey' | 'koreaderSyncUsername' | 'localSourcePath' | 'maxLogFileSize' | 'maxLogFiles' | 'maxLogFolderSize' | 'maxSourcesInParallel' | 'opdsChapterSortOrder' | 'opdsEnablePageReadProgress' | 'opdsItemsPerPage' | 'opdsMarkAsReadOnDownload' | 'opdsShowOnlyDownloadedChapters' | 'opdsShowOnlyUnreadChapters' | 'opdsUseBinaryFileSizes' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPassword' | 'socksProxyPort' | 'socksProxyUsername' | 'socksProxyVersion' | 'systemTrayEnabled' | 'updateMangas' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | SettingsTypeKeySpecifier)[];
|
||||||
export type SettingsTypeFieldPolicy = {
|
export type SettingsTypeFieldPolicy = {
|
||||||
authMode?: FieldPolicy<any> | FieldReadFunction<any>,
|
authMode?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
authPassword?: FieldPolicy<any> | FieldReadFunction<any>,
|
authPassword?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -817,6 +877,16 @@ export type SettingsTypeFieldPolicy = {
|
|||||||
gqlDebugLogsEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
gqlDebugLogsEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
initialOpenInBrowserEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
initialOpenInBrowserEnabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
ip?: FieldPolicy<any> | FieldReadFunction<any>,
|
ip?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtAudience?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtRefreshExpiry?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
jwtTokenExpiry?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncChecksumMethod?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncDeviceId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncPercentageTolerance?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncServerUrl?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncStrategy?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncUserkey?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
koreaderSyncUsername?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
localSourcePath?: FieldPolicy<any> | FieldReadFunction<any>,
|
localSourcePath?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
maxLogFileSize?: FieldPolicy<any> | FieldReadFunction<any>,
|
maxLogFileSize?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
maxLogFiles?: FieldPolicy<any> | FieldReadFunction<any>,
|
maxLogFiles?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -873,8 +943,9 @@ export type SourceNodeListFieldPolicy = {
|
|||||||
pageInfo?: FieldPolicy<any> | FieldReadFunction<any>,
|
pageInfo?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
totalCount?: FieldPolicy<any> | FieldReadFunction<any>
|
totalCount?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type SourceTypeKeySpecifier = ('displayName' | 'extension' | 'filters' | 'iconUrl' | 'id' | 'isConfigurable' | 'isNsfw' | 'lang' | 'manga' | 'meta' | 'name' | 'preferences' | 'supportsLatest' | SourceTypeKeySpecifier)[];
|
export type SourceTypeKeySpecifier = ('baseUrl' | 'displayName' | 'extension' | 'filters' | 'iconUrl' | 'id' | 'isConfigurable' | 'isNsfw' | 'lang' | 'manga' | 'meta' | 'name' | 'preferences' | 'supportsLatest' | SourceTypeKeySpecifier)[];
|
||||||
export type SourceTypeFieldPolicy = {
|
export type SourceTypeFieldPolicy = {
|
||||||
|
baseUrl?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
displayName?: FieldPolicy<any> | FieldReadFunction<any>,
|
displayName?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
extension?: FieldPolicy<any> | FieldReadFunction<any>,
|
extension?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
filters?: FieldPolicy<any> | FieldReadFunction<any>,
|
filters?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -907,15 +978,21 @@ export type SubscriptionFieldPolicy = {
|
|||||||
updateStatusChanged?: FieldPolicy<any> | FieldReadFunction<any>,
|
updateStatusChanged?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
webUIUpdateStatusChange?: FieldPolicy<any> | FieldReadFunction<any>
|
webUIUpdateStatusChange?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type SwitchPreferenceKeySpecifier = ('currentValue' | 'default' | 'key' | 'summary' | 'title' | 'visible' | SwitchPreferenceKeySpecifier)[];
|
export type SwitchPreferenceKeySpecifier = ('currentValue' | 'default' | 'enabled' | 'key' | 'summary' | 'title' | 'visible' | SwitchPreferenceKeySpecifier)[];
|
||||||
export type SwitchPreferenceFieldPolicy = {
|
export type SwitchPreferenceFieldPolicy = {
|
||||||
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
currentValue?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
enabled?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
key?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
summary?: FieldPolicy<any> | FieldReadFunction<any>,
|
summary?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
visible?: FieldPolicy<any> | FieldReadFunction<any>
|
visible?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
|
export type SyncConflictInfoTypeKeySpecifier = ('deviceName' | 'remotePage' | SyncConflictInfoTypeKeySpecifier)[];
|
||||||
|
export type SyncConflictInfoTypeFieldPolicy = {
|
||||||
|
deviceName?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
remotePage?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
|
};
|
||||||
export type TextFilterKeySpecifier = ('default' | 'name' | TextFilterKeySpecifier)[];
|
export type TextFilterKeySpecifier = ('default' | 'name' | TextFilterKeySpecifier)[];
|
||||||
export type TextFilterFieldPolicy = {
|
export type TextFilterFieldPolicy = {
|
||||||
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
default?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -1396,6 +1473,14 @@ export type StrictTypedTypePolicies = {
|
|||||||
keyFields?: false | InstallExternalExtensionPayloadKeySpecifier | (() => undefined | InstallExternalExtensionPayloadKeySpecifier),
|
keyFields?: false | InstallExternalExtensionPayloadKeySpecifier | (() => undefined | InstallExternalExtensionPayloadKeySpecifier),
|
||||||
fields?: InstallExternalExtensionPayloadFieldPolicy,
|
fields?: InstallExternalExtensionPayloadFieldPolicy,
|
||||||
},
|
},
|
||||||
|
KoSyncConnectPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
|
keyFields?: false | KoSyncConnectPayloadKeySpecifier | (() => undefined | KoSyncConnectPayloadKeySpecifier),
|
||||||
|
fields?: KoSyncConnectPayloadFieldPolicy,
|
||||||
|
},
|
||||||
|
KoSyncStatusPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
|
keyFields?: false | KoSyncStatusPayloadKeySpecifier | (() => undefined | KoSyncStatusPayloadKeySpecifier),
|
||||||
|
fields?: KoSyncStatusPayloadFieldPolicy,
|
||||||
|
},
|
||||||
LastUpdateTimestampPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
LastUpdateTimestampPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
keyFields?: false | LastUpdateTimestampPayloadKeySpecifier | (() => undefined | LastUpdateTimestampPayloadKeySpecifier),
|
keyFields?: false | LastUpdateTimestampPayloadKeySpecifier | (() => undefined | LastUpdateTimestampPayloadKeySpecifier),
|
||||||
fields?: LastUpdateTimestampPayloadFieldPolicy,
|
fields?: LastUpdateTimestampPayloadFieldPolicy,
|
||||||
@@ -1408,6 +1493,10 @@ export type StrictTypedTypePolicies = {
|
|||||||
keyFields?: false | ListPreferenceKeySpecifier | (() => undefined | ListPreferenceKeySpecifier),
|
keyFields?: false | ListPreferenceKeySpecifier | (() => undefined | ListPreferenceKeySpecifier),
|
||||||
fields?: ListPreferenceFieldPolicy,
|
fields?: ListPreferenceFieldPolicy,
|
||||||
},
|
},
|
||||||
|
LoginPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
|
keyFields?: false | LoginPayloadKeySpecifier | (() => undefined | LoginPayloadKeySpecifier),
|
||||||
|
fields?: LoginPayloadFieldPolicy,
|
||||||
|
},
|
||||||
LoginTrackerCredentialsPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
LoginTrackerCredentialsPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
keyFields?: false | LoginTrackerCredentialsPayloadKeySpecifier | (() => undefined | LoginTrackerCredentialsPayloadKeySpecifier),
|
keyFields?: false | LoginTrackerCredentialsPayloadKeySpecifier | (() => undefined | LoginTrackerCredentialsPayloadKeySpecifier),
|
||||||
fields?: LoginTrackerCredentialsPayloadFieldPolicy,
|
fields?: LoginTrackerCredentialsPayloadFieldPolicy,
|
||||||
@@ -1416,6 +1505,10 @@ export type StrictTypedTypePolicies = {
|
|||||||
keyFields?: false | LoginTrackerOAuthPayloadKeySpecifier | (() => undefined | LoginTrackerOAuthPayloadKeySpecifier),
|
keyFields?: false | LoginTrackerOAuthPayloadKeySpecifier | (() => undefined | LoginTrackerOAuthPayloadKeySpecifier),
|
||||||
fields?: LoginTrackerOAuthPayloadFieldPolicy,
|
fields?: LoginTrackerOAuthPayloadFieldPolicy,
|
||||||
},
|
},
|
||||||
|
LogoutKoSyncAccountPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
|
keyFields?: false | LogoutKoSyncAccountPayloadKeySpecifier | (() => undefined | LogoutKoSyncAccountPayloadKeySpecifier),
|
||||||
|
fields?: LogoutKoSyncAccountPayloadFieldPolicy,
|
||||||
|
},
|
||||||
LogoutTrackerPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
LogoutTrackerPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
keyFields?: false | LogoutTrackerPayloadKeySpecifier | (() => undefined | LogoutTrackerPayloadKeySpecifier),
|
keyFields?: false | LogoutTrackerPayloadKeySpecifier | (() => undefined | LogoutTrackerPayloadKeySpecifier),
|
||||||
fields?: LogoutTrackerPayloadFieldPolicy,
|
fields?: LogoutTrackerPayloadFieldPolicy,
|
||||||
@@ -1472,6 +1565,10 @@ export type StrictTypedTypePolicies = {
|
|||||||
keyFields?: false | QueryKeySpecifier | (() => undefined | QueryKeySpecifier),
|
keyFields?: false | QueryKeySpecifier | (() => undefined | QueryKeySpecifier),
|
||||||
fields?: QueryFieldPolicy,
|
fields?: QueryFieldPolicy,
|
||||||
},
|
},
|
||||||
|
RefreshTokenPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
|
keyFields?: false | RefreshTokenPayloadKeySpecifier | (() => undefined | RefreshTokenPayloadKeySpecifier),
|
||||||
|
fields?: RefreshTokenPayloadFieldPolicy,
|
||||||
|
},
|
||||||
ReorderChapterDownloadPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
ReorderChapterDownloadPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
keyFields?: false | ReorderChapterDownloadPayloadKeySpecifier | (() => undefined | ReorderChapterDownloadPayloadKeySpecifier),
|
keyFields?: false | ReorderChapterDownloadPayloadKeySpecifier | (() => undefined | ReorderChapterDownloadPayloadKeySpecifier),
|
||||||
fields?: ReorderChapterDownloadPayloadFieldPolicy,
|
fields?: ReorderChapterDownloadPayloadFieldPolicy,
|
||||||
@@ -1576,6 +1673,10 @@ export type StrictTypedTypePolicies = {
|
|||||||
keyFields?: false | SwitchPreferenceKeySpecifier | (() => undefined | SwitchPreferenceKeySpecifier),
|
keyFields?: false | SwitchPreferenceKeySpecifier | (() => undefined | SwitchPreferenceKeySpecifier),
|
||||||
fields?: SwitchPreferenceFieldPolicy,
|
fields?: SwitchPreferenceFieldPolicy,
|
||||||
},
|
},
|
||||||
|
SyncConflictInfoType?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
|
keyFields?: false | SyncConflictInfoTypeKeySpecifier | (() => undefined | SyncConflictInfoTypeKeySpecifier),
|
||||||
|
fields?: SyncConflictInfoTypeFieldPolicy,
|
||||||
|
},
|
||||||
TextFilter?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
TextFilter?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||||
keyFields?: false | TextFilterKeySpecifier | (() => undefined | TextFilterKeySpecifier),
|
keyFields?: false | TextFilterKeySpecifier | (() => undefined | TextFilterKeySpecifier),
|
||||||
fields?: TextFilterFieldPolicy,
|
fields?: TextFilterFieldPolicy,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export type Scalars = {
|
|||||||
Int: { input: number; output: number; }
|
Int: { input: number; output: number; }
|
||||||
Float: { input: number; output: number; }
|
Float: { input: number; output: number; }
|
||||||
Cursor: { input: string; output: string; }
|
Cursor: { input: string; output: string; }
|
||||||
|
Duration: { input: any; output: any; }
|
||||||
LongString: { input: string; output: string; }
|
LongString: { input: string; output: string; }
|
||||||
Upload: { input: any; output: any; }
|
Upload: { input: any; output: any; }
|
||||||
};
|
};
|
||||||
@@ -38,7 +39,8 @@ export type AboutWebUi = {
|
|||||||
export enum AuthMode {
|
export enum AuthMode {
|
||||||
BasicAuth = 'BASIC_AUTH',
|
BasicAuth = 'BASIC_AUTH',
|
||||||
None = 'NONE',
|
None = 'NONE',
|
||||||
SimpleLogin = 'SIMPLE_LOGIN'
|
SimpleLogin = 'SIMPLE_LOGIN',
|
||||||
|
UiLogin = 'UI_LOGIN'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum BackupRestoreState {
|
export enum BackupRestoreState {
|
||||||
@@ -287,6 +289,7 @@ export type CheckBoxPreference = {
|
|||||||
__typename?: 'CheckBoxPreference';
|
__typename?: 'CheckBoxPreference';
|
||||||
currentValue?: Maybe<Scalars['Boolean']['output']>;
|
currentValue?: Maybe<Scalars['Boolean']['output']>;
|
||||||
default: Scalars['Boolean']['output'];
|
default: Scalars['Boolean']['output'];
|
||||||
|
enabled: Scalars['Boolean']['output'];
|
||||||
key: Scalars['String']['output'];
|
key: Scalars['String']['output'];
|
||||||
summary?: Maybe<Scalars['String']['output']>;
|
summary?: Maybe<Scalars['String']['output']>;
|
||||||
title?: Maybe<Scalars['String']['output']>;
|
title?: Maybe<Scalars['String']['output']>;
|
||||||
@@ -325,6 +328,12 @@ export type ClearDownloaderPayload = {
|
|||||||
downloadStatus: DownloadStatus;
|
downloadStatus: DownloadStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ConnectKoSyncAccountInput = {
|
||||||
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
password: Scalars['String']['input'];
|
||||||
|
username: Scalars['String']['input'];
|
||||||
|
};
|
||||||
|
|
||||||
export type CreateBackupInput = {
|
export type CreateBackupInput = {
|
||||||
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
includeCategories?: InputMaybe<Scalars['Boolean']['input']>;
|
includeCategories?: InputMaybe<Scalars['Boolean']['input']>;
|
||||||
@@ -576,6 +585,7 @@ export type EditTextPreference = {
|
|||||||
default?: Maybe<Scalars['String']['output']>;
|
default?: Maybe<Scalars['String']['output']>;
|
||||||
dialogMessage?: Maybe<Scalars['String']['output']>;
|
dialogMessage?: Maybe<Scalars['String']['output']>;
|
||||||
dialogTitle?: Maybe<Scalars['String']['output']>;
|
dialogTitle?: Maybe<Scalars['String']['output']>;
|
||||||
|
enabled: Scalars['Boolean']['output'];
|
||||||
key: Scalars['String']['output'];
|
key: Scalars['String']['output'];
|
||||||
summary?: Maybe<Scalars['String']['output']>;
|
summary?: Maybe<Scalars['String']['output']>;
|
||||||
text?: Maybe<Scalars['String']['output']>;
|
text?: Maybe<Scalars['String']['output']>;
|
||||||
@@ -691,6 +701,7 @@ export type FetchChapterPagesPayload = {
|
|||||||
chapter: ChapterType;
|
chapter: ChapterType;
|
||||||
clientMutationId?: Maybe<Scalars['String']['output']>;
|
clientMutationId?: Maybe<Scalars['String']['output']>;
|
||||||
pages: Array<Scalars['String']['output']>;
|
pages: Array<Scalars['String']['output']>;
|
||||||
|
syncConflict?: Maybe<SyncConflictInfoType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FetchChaptersInput = {
|
export type FetchChaptersInput = {
|
||||||
@@ -853,6 +864,34 @@ export type IntFilterInput = {
|
|||||||
notIn?: InputMaybe<Array<Scalars['Int']['input']>>;
|
notIn?: InputMaybe<Array<Scalars['Int']['input']>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type KoSyncConnectPayload = {
|
||||||
|
__typename?: 'KoSyncConnectPayload';
|
||||||
|
clientMutationId?: Maybe<Scalars['String']['output']>;
|
||||||
|
message?: Maybe<Scalars['String']['output']>;
|
||||||
|
settings: SettingsType;
|
||||||
|
success: Scalars['Boolean']['output'];
|
||||||
|
username?: Maybe<Scalars['String']['output']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type KoSyncStatusPayload = {
|
||||||
|
__typename?: 'KoSyncStatusPayload';
|
||||||
|
isLoggedIn: Scalars['Boolean']['output'];
|
||||||
|
username?: Maybe<Scalars['String']['output']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum KoreaderSyncChecksumMethod {
|
||||||
|
Binary = 'BINARY',
|
||||||
|
Filename = 'FILENAME'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum KoreaderSyncStrategy {
|
||||||
|
Disabled = 'DISABLED',
|
||||||
|
Prompt = 'PROMPT',
|
||||||
|
Receive = 'RECEIVE',
|
||||||
|
Send = 'SEND',
|
||||||
|
Silent = 'SILENT'
|
||||||
|
}
|
||||||
|
|
||||||
export type LastUpdateTimestampPayload = {
|
export type LastUpdateTimestampPayload = {
|
||||||
__typename?: 'LastUpdateTimestampPayload';
|
__typename?: 'LastUpdateTimestampPayload';
|
||||||
timestamp: Scalars['LongString']['output'];
|
timestamp: Scalars['LongString']['output'];
|
||||||
@@ -874,6 +913,7 @@ export type ListPreference = {
|
|||||||
__typename?: 'ListPreference';
|
__typename?: 'ListPreference';
|
||||||
currentValue?: Maybe<Scalars['String']['output']>;
|
currentValue?: Maybe<Scalars['String']['output']>;
|
||||||
default?: Maybe<Scalars['String']['output']>;
|
default?: Maybe<Scalars['String']['output']>;
|
||||||
|
enabled: Scalars['Boolean']['output'];
|
||||||
entries: Array<Scalars['String']['output']>;
|
entries: Array<Scalars['String']['output']>;
|
||||||
entryValues: Array<Scalars['String']['output']>;
|
entryValues: Array<Scalars['String']['output']>;
|
||||||
key: Scalars['String']['output'];
|
key: Scalars['String']['output'];
|
||||||
@@ -882,6 +922,19 @@ export type ListPreference = {
|
|||||||
visible: Scalars['Boolean']['output'];
|
visible: Scalars['Boolean']['output'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LoginInput = {
|
||||||
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
password: Scalars['String']['input'];
|
||||||
|
username: Scalars['String']['input'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LoginPayload = {
|
||||||
|
__typename?: 'LoginPayload';
|
||||||
|
accessToken: Scalars['String']['output'];
|
||||||
|
clientMutationId?: Maybe<Scalars['String']['output']>;
|
||||||
|
refreshToken: Scalars['String']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
export type LoginTrackerCredentialsInput = {
|
export type LoginTrackerCredentialsInput = {
|
||||||
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
password: Scalars['String']['input'];
|
password: Scalars['String']['input'];
|
||||||
@@ -909,6 +962,17 @@ export type LoginTrackerOAuthPayload = {
|
|||||||
tracker: TrackerType;
|
tracker: TrackerType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LogoutKoSyncAccountInput = {
|
||||||
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LogoutKoSyncAccountPayload = {
|
||||||
|
__typename?: 'LogoutKoSyncAccountPayload';
|
||||||
|
clientMutationId?: Maybe<Scalars['String']['output']>;
|
||||||
|
settings: SettingsType;
|
||||||
|
success: Scalars['Boolean']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
export type LogoutTrackerInput = {
|
export type LogoutTrackerInput = {
|
||||||
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
trackerId: Scalars['Int']['input'];
|
trackerId: Scalars['Int']['input'];
|
||||||
@@ -1143,6 +1207,7 @@ export type MultiSelectListPreference = {
|
|||||||
default?: Maybe<Array<Scalars['String']['output']>>;
|
default?: Maybe<Array<Scalars['String']['output']>>;
|
||||||
dialogMessage?: Maybe<Scalars['String']['output']>;
|
dialogMessage?: Maybe<Scalars['String']['output']>;
|
||||||
dialogTitle?: Maybe<Scalars['String']['output']>;
|
dialogTitle?: Maybe<Scalars['String']['output']>;
|
||||||
|
enabled: Scalars['Boolean']['output'];
|
||||||
entries: Array<Scalars['String']['output']>;
|
entries: Array<Scalars['String']['output']>;
|
||||||
entryValues: Array<Scalars['String']['output']>;
|
entryValues: Array<Scalars['String']['output']>;
|
||||||
key: Scalars['String']['output'];
|
key: Scalars['String']['output'];
|
||||||
@@ -1156,6 +1221,7 @@ export type Mutation = {
|
|||||||
bindTrack: BindTrackPayload;
|
bindTrack: BindTrackPayload;
|
||||||
clearCachedImages: ClearCachedImagesPayload;
|
clearCachedImages: ClearCachedImagesPayload;
|
||||||
clearDownloader?: Maybe<ClearDownloaderPayload>;
|
clearDownloader?: Maybe<ClearDownloaderPayload>;
|
||||||
|
connectKoSyncAccount: KoSyncConnectPayload;
|
||||||
createBackup: CreateBackupPayload;
|
createBackup: CreateBackupPayload;
|
||||||
createCategory?: Maybe<CreateCategoryPayload>;
|
createCategory?: Maybe<CreateCategoryPayload>;
|
||||||
deleteCategory?: Maybe<DeleteCategoryPayload>;
|
deleteCategory?: Maybe<DeleteCategoryPayload>;
|
||||||
@@ -1177,9 +1243,12 @@ export type Mutation = {
|
|||||||
fetchSourceManga?: Maybe<FetchSourceMangaPayload>;
|
fetchSourceManga?: Maybe<FetchSourceMangaPayload>;
|
||||||
fetchTrack: FetchTrackPayload;
|
fetchTrack: FetchTrackPayload;
|
||||||
installExternalExtension?: Maybe<InstallExternalExtensionPayload>;
|
installExternalExtension?: Maybe<InstallExternalExtensionPayload>;
|
||||||
|
login: LoginPayload;
|
||||||
loginTrackerCredentials: LoginTrackerCredentialsPayload;
|
loginTrackerCredentials: LoginTrackerCredentialsPayload;
|
||||||
loginTrackerOAuth: LoginTrackerOAuthPayload;
|
loginTrackerOAuth: LoginTrackerOAuthPayload;
|
||||||
|
logoutKoSyncAccount: LogoutKoSyncAccountPayload;
|
||||||
logoutTracker: LogoutTrackerPayload;
|
logoutTracker: LogoutTrackerPayload;
|
||||||
|
refreshToken: RefreshTokenPayload;
|
||||||
reorderChapterDownload?: Maybe<ReorderChapterDownloadPayload>;
|
reorderChapterDownload?: Maybe<ReorderChapterDownloadPayload>;
|
||||||
resetSettings: ResetSettingsPayload;
|
resetSettings: ResetSettingsPayload;
|
||||||
resetWebUIUpdateStatus?: Maybe<WebUiUpdateStatus>;
|
resetWebUIUpdateStatus?: Maybe<WebUiUpdateStatus>;
|
||||||
@@ -1230,6 +1299,11 @@ export type MutationClearDownloaderArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationConnectKoSyncAccountArgs = {
|
||||||
|
input: ConnectKoSyncAccountInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateBackupArgs = {
|
export type MutationCreateBackupArgs = {
|
||||||
input?: InputMaybe<CreateBackupInput>;
|
input?: InputMaybe<CreateBackupInput>;
|
||||||
};
|
};
|
||||||
@@ -1335,6 +1409,11 @@ export type MutationInstallExternalExtensionArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationLoginArgs = {
|
||||||
|
input: LoginInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationLoginTrackerCredentialsArgs = {
|
export type MutationLoginTrackerCredentialsArgs = {
|
||||||
input: LoginTrackerCredentialsInput;
|
input: LoginTrackerCredentialsInput;
|
||||||
};
|
};
|
||||||
@@ -1345,11 +1424,21 @@ export type MutationLoginTrackerOAuthArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationLogoutKoSyncAccountArgs = {
|
||||||
|
input: LogoutKoSyncAccountInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationLogoutTrackerArgs = {
|
export type MutationLogoutTrackerArgs = {
|
||||||
input: LogoutTrackerInput;
|
input: LogoutTrackerInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationRefreshTokenArgs = {
|
||||||
|
input: RefreshTokenInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationReorderChapterDownloadArgs = {
|
export type MutationReorderChapterDownloadArgs = {
|
||||||
input: ReorderChapterDownloadInput;
|
input: ReorderChapterDownloadInput;
|
||||||
};
|
};
|
||||||
@@ -1570,6 +1659,16 @@ export type PartialSettingsType = Settings & {
|
|||||||
gqlDebugLogsEnabled?: Maybe<Scalars['Boolean']['output']>;
|
gqlDebugLogsEnabled?: Maybe<Scalars['Boolean']['output']>;
|
||||||
initialOpenInBrowserEnabled?: Maybe<Scalars['Boolean']['output']>;
|
initialOpenInBrowserEnabled?: Maybe<Scalars['Boolean']['output']>;
|
||||||
ip?: Maybe<Scalars['String']['output']>;
|
ip?: Maybe<Scalars['String']['output']>;
|
||||||
|
jwtAudience?: Maybe<Scalars['String']['output']>;
|
||||||
|
jwtRefreshExpiry?: Maybe<Scalars['Duration']['output']>;
|
||||||
|
jwtTokenExpiry?: Maybe<Scalars['Duration']['output']>;
|
||||||
|
koreaderSyncChecksumMethod?: Maybe<KoreaderSyncChecksumMethod>;
|
||||||
|
koreaderSyncDeviceId?: Maybe<Scalars['String']['output']>;
|
||||||
|
koreaderSyncPercentageTolerance?: Maybe<Scalars['Float']['output']>;
|
||||||
|
koreaderSyncServerUrl?: Maybe<Scalars['String']['output']>;
|
||||||
|
koreaderSyncStrategy?: Maybe<KoreaderSyncStrategy>;
|
||||||
|
koreaderSyncUserkey?: Maybe<Scalars['String']['output']>;
|
||||||
|
koreaderSyncUsername?: Maybe<Scalars['String']['output']>;
|
||||||
localSourcePath?: Maybe<Scalars['String']['output']>;
|
localSourcePath?: Maybe<Scalars['String']['output']>;
|
||||||
maxLogFileSize?: Maybe<Scalars['String']['output']>;
|
maxLogFileSize?: Maybe<Scalars['String']['output']>;
|
||||||
maxLogFiles?: Maybe<Scalars['Int']['output']>;
|
maxLogFiles?: Maybe<Scalars['Int']['output']>;
|
||||||
@@ -1627,6 +1726,16 @@ export type PartialSettingsTypeInput = {
|
|||||||
globalUpdateInterval?: InputMaybe<Scalars['Float']['input']>;
|
globalUpdateInterval?: InputMaybe<Scalars['Float']['input']>;
|
||||||
initialOpenInBrowserEnabled?: InputMaybe<Scalars['Boolean']['input']>;
|
initialOpenInBrowserEnabled?: InputMaybe<Scalars['Boolean']['input']>;
|
||||||
ip?: InputMaybe<Scalars['String']['input']>;
|
ip?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
jwtAudience?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
jwtRefreshExpiry?: InputMaybe<Scalars['Duration']['input']>;
|
||||||
|
jwtTokenExpiry?: InputMaybe<Scalars['Duration']['input']>;
|
||||||
|
koreaderSyncChecksumMethod?: InputMaybe<KoreaderSyncChecksumMethod>;
|
||||||
|
koreaderSyncDeviceId?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
koreaderSyncPercentageTolerance?: InputMaybe<Scalars['Float']['input']>;
|
||||||
|
koreaderSyncServerUrl?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
koreaderSyncStrategy?: InputMaybe<KoreaderSyncStrategy>;
|
||||||
|
koreaderSyncUserkey?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
koreaderSyncUsername?: InputMaybe<Scalars['String']['input']>;
|
||||||
localSourcePath?: InputMaybe<Scalars['String']['input']>;
|
localSourcePath?: InputMaybe<Scalars['String']['input']>;
|
||||||
maxLogFileSize?: InputMaybe<Scalars['String']['input']>;
|
maxLogFileSize?: InputMaybe<Scalars['String']['input']>;
|
||||||
maxLogFiles?: InputMaybe<Scalars['Int']['input']>;
|
maxLogFiles?: InputMaybe<Scalars['Int']['input']>;
|
||||||
@@ -1670,6 +1779,7 @@ export type Query = {
|
|||||||
extension: ExtensionType;
|
extension: ExtensionType;
|
||||||
extensions: ExtensionNodeList;
|
extensions: ExtensionNodeList;
|
||||||
getWebUIUpdateStatus: WebUiUpdateStatus;
|
getWebUIUpdateStatus: WebUiUpdateStatus;
|
||||||
|
koSyncStatus: KoSyncStatusPayload;
|
||||||
lastUpdateTimestamp: LastUpdateTimestampPayload;
|
lastUpdateTimestamp: LastUpdateTimestampPayload;
|
||||||
libraryUpdateStatus: LibraryUpdateStatus;
|
libraryUpdateStatus: LibraryUpdateStatus;
|
||||||
manga: MangaType;
|
manga: MangaType;
|
||||||
@@ -1856,6 +1966,17 @@ export type QueryValidateBackupArgs = {
|
|||||||
input: ValidateBackupInput;
|
input: ValidateBackupInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type RefreshTokenInput = {
|
||||||
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
refreshToken: Scalars['String']['input'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RefreshTokenPayload = {
|
||||||
|
__typename?: 'RefreshTokenPayload';
|
||||||
|
accessToken: Scalars['String']['output'];
|
||||||
|
clientMutationId?: Maybe<Scalars['String']['output']>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ReorderChapterDownloadInput = {
|
export type ReorderChapterDownloadInput = {
|
||||||
chapterId: Scalars['Int']['input'];
|
chapterId: Scalars['Int']['input'];
|
||||||
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||||
@@ -2018,6 +2139,16 @@ export type Settings = {
|
|||||||
gqlDebugLogsEnabled?: Maybe<Scalars['Boolean']['output']>;
|
gqlDebugLogsEnabled?: Maybe<Scalars['Boolean']['output']>;
|
||||||
initialOpenInBrowserEnabled?: Maybe<Scalars['Boolean']['output']>;
|
initialOpenInBrowserEnabled?: Maybe<Scalars['Boolean']['output']>;
|
||||||
ip?: Maybe<Scalars['String']['output']>;
|
ip?: Maybe<Scalars['String']['output']>;
|
||||||
|
jwtAudience?: Maybe<Scalars['String']['output']>;
|
||||||
|
jwtRefreshExpiry?: Maybe<Scalars['Duration']['output']>;
|
||||||
|
jwtTokenExpiry?: Maybe<Scalars['Duration']['output']>;
|
||||||
|
koreaderSyncChecksumMethod?: Maybe<KoreaderSyncChecksumMethod>;
|
||||||
|
koreaderSyncDeviceId?: Maybe<Scalars['String']['output']>;
|
||||||
|
koreaderSyncPercentageTolerance?: Maybe<Scalars['Float']['output']>;
|
||||||
|
koreaderSyncServerUrl?: Maybe<Scalars['String']['output']>;
|
||||||
|
koreaderSyncStrategy?: Maybe<KoreaderSyncStrategy>;
|
||||||
|
koreaderSyncUserkey?: Maybe<Scalars['String']['output']>;
|
||||||
|
koreaderSyncUsername?: Maybe<Scalars['String']['output']>;
|
||||||
localSourcePath?: Maybe<Scalars['String']['output']>;
|
localSourcePath?: Maybe<Scalars['String']['output']>;
|
||||||
maxLogFileSize?: Maybe<Scalars['String']['output']>;
|
maxLogFileSize?: Maybe<Scalars['String']['output']>;
|
||||||
maxLogFiles?: Maybe<Scalars['Int']['output']>;
|
maxLogFiles?: Maybe<Scalars['Int']['output']>;
|
||||||
@@ -2105,6 +2236,16 @@ export type SettingsType = Settings & {
|
|||||||
gqlDebugLogsEnabled: Scalars['Boolean']['output'];
|
gqlDebugLogsEnabled: Scalars['Boolean']['output'];
|
||||||
initialOpenInBrowserEnabled: Scalars['Boolean']['output'];
|
initialOpenInBrowserEnabled: Scalars['Boolean']['output'];
|
||||||
ip: Scalars['String']['output'];
|
ip: Scalars['String']['output'];
|
||||||
|
jwtAudience: Scalars['String']['output'];
|
||||||
|
jwtRefreshExpiry: Scalars['Duration']['output'];
|
||||||
|
jwtTokenExpiry: Scalars['Duration']['output'];
|
||||||
|
koreaderSyncChecksumMethod: KoreaderSyncChecksumMethod;
|
||||||
|
koreaderSyncDeviceId: Scalars['String']['output'];
|
||||||
|
koreaderSyncPercentageTolerance: Scalars['Float']['output'];
|
||||||
|
koreaderSyncServerUrl: Scalars['String']['output'];
|
||||||
|
koreaderSyncStrategy: KoreaderSyncStrategy;
|
||||||
|
koreaderSyncUserkey: Scalars['String']['output'];
|
||||||
|
koreaderSyncUsername: Scalars['String']['output'];
|
||||||
localSourcePath: Scalars['String']['output'];
|
localSourcePath: Scalars['String']['output'];
|
||||||
maxLogFileSize: Scalars['String']['output'];
|
maxLogFileSize: Scalars['String']['output'];
|
||||||
maxLogFiles: Scalars['Int']['output'];
|
maxLogFiles: Scalars['Int']['output'];
|
||||||
@@ -2226,6 +2367,7 @@ export type SourcePreferenceChangeInput = {
|
|||||||
|
|
||||||
export type SourceType = {
|
export type SourceType = {
|
||||||
__typename?: 'SourceType';
|
__typename?: 'SourceType';
|
||||||
|
baseUrl?: Maybe<Scalars['String']['output']>;
|
||||||
displayName: Scalars['String']['output'];
|
displayName: Scalars['String']['output'];
|
||||||
extension: ExtensionType;
|
extension: ExtensionType;
|
||||||
filters: Array<Filter>;
|
filters: Array<Filter>;
|
||||||
@@ -2362,12 +2504,19 @@ export type SwitchPreference = {
|
|||||||
__typename?: 'SwitchPreference';
|
__typename?: 'SwitchPreference';
|
||||||
currentValue?: Maybe<Scalars['Boolean']['output']>;
|
currentValue?: Maybe<Scalars['Boolean']['output']>;
|
||||||
default: Scalars['Boolean']['output'];
|
default: Scalars['Boolean']['output'];
|
||||||
|
enabled: Scalars['Boolean']['output'];
|
||||||
key: Scalars['String']['output'];
|
key: Scalars['String']['output'];
|
||||||
summary?: Maybe<Scalars['String']['output']>;
|
summary?: Maybe<Scalars['String']['output']>;
|
||||||
title?: Maybe<Scalars['String']['output']>;
|
title?: Maybe<Scalars['String']['output']>;
|
||||||
visible: Scalars['Boolean']['output'];
|
visible: Scalars['Boolean']['output'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SyncConflictInfoType = {
|
||||||
|
__typename?: 'SyncConflictInfoType';
|
||||||
|
deviceName: Scalars['String']['output'];
|
||||||
|
remotePage: Scalars['Int']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
export type TextFilter = {
|
export type TextFilter = {
|
||||||
__typename?: 'TextFilter';
|
__typename?: 'TextFilter';
|
||||||
default: Scalars['String']['output'];
|
default: Scalars['String']['output'];
|
||||||
@@ -2994,7 +3143,7 @@ export type MangaScreenFieldsFragment = { __typename?: 'MangaType', artist?: str
|
|||||||
|
|
||||||
export type MangaLibraryDuplicateScreenFieldsFragment = { __typename?: 'MangaType', description?: string | null, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, unreadCount: number, downloadCount: number, bookmarkCount: number, hasDuplicateChapters: boolean, chapters: { __typename?: 'ChapterNodeList', totalCount: number } };
|
export type MangaLibraryDuplicateScreenFieldsFragment = { __typename?: 'MangaType', description?: string | null, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, unreadCount: number, downloadCount: number, bookmarkCount: number, hasDuplicateChapters: boolean, chapters: { __typename?: 'ChapterNodeList', totalCount: number } };
|
||||||
|
|
||||||
export type ServerSettingsFragment = { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> };
|
export type ServerSettingsFragment = { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, jwtAudience: string, jwtTokenExpiry: any, jwtRefreshExpiry: any, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> };
|
||||||
|
|
||||||
export type SourceMetaFieldsFragment = { __typename?: 'SourceMetaType', sourceId: string, key: string, value: string };
|
export type SourceMetaFieldsFragment = { __typename?: 'SourceMetaType', sourceId: string, key: string, value: string };
|
||||||
|
|
||||||
@@ -3356,14 +3505,14 @@ export type ResetServerSettingsMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ResetServerSettingsMutation = { __typename?: 'Mutation', resetSettings: { __typename?: 'ResetSettingsPayload', settings: { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> } } };
|
export type ResetServerSettingsMutation = { __typename?: 'Mutation', resetSettings: { __typename?: 'ResetSettingsPayload', settings: { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, jwtAudience: string, jwtTokenExpiry: any, jwtRefreshExpiry: any, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> } } };
|
||||||
|
|
||||||
export type UpdateServerSettingsMutationVariables = Exact<{
|
export type UpdateServerSettingsMutationVariables = Exact<{
|
||||||
input: SetSettingsInput;
|
input: SetSettingsInput;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type UpdateServerSettingsMutation = { __typename?: 'Mutation', setSettings: { __typename?: 'SetSettingsPayload', settings: { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> } } };
|
export type UpdateServerSettingsMutation = { __typename?: 'Mutation', setSettings: { __typename?: 'SetSettingsPayload', settings: { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, jwtAudience: string, jwtTokenExpiry: any, jwtRefreshExpiry: any, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> } } };
|
||||||
|
|
||||||
export type GetSourceMangasFetchMutationVariables = Exact<{
|
export type GetSourceMangasFetchMutationVariables = Exact<{
|
||||||
input: FetchSourceMangaInput;
|
input: FetchSourceMangaInput;
|
||||||
@@ -3456,6 +3605,21 @@ export type StopUpdaterMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type StopUpdaterMutation = { __typename?: 'Mutation', updateStop: { __typename?: 'UpdateStopPayload', clientMutationId?: string | null } };
|
export type StopUpdaterMutation = { __typename?: 'Mutation', updateStop: { __typename?: 'UpdateStopPayload', clientMutationId?: string | null } };
|
||||||
|
|
||||||
|
export type UserLoginMutationVariables = Exact<{
|
||||||
|
password: Scalars['String']['input'];
|
||||||
|
username: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type UserLoginMutation = { __typename?: 'Mutation', login: { __typename?: 'LoginPayload', accessToken: string, refreshToken: string } };
|
||||||
|
|
||||||
|
export type UserRefreshMutationVariables = Exact<{
|
||||||
|
refreshToken: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type UserRefreshMutation = { __typename?: 'Mutation', refreshToken: { __typename?: 'RefreshTokenPayload', accessToken: string } };
|
||||||
|
|
||||||
export type ValidateBackupQueryVariables = Exact<{
|
export type ValidateBackupQueryVariables = Exact<{
|
||||||
backup: Scalars['Upload']['input'];
|
backup: Scalars['Upload']['input'];
|
||||||
}>;
|
}>;
|
||||||
@@ -3747,7 +3911,7 @@ export type GetWebuiUpdateStatusQuery = { __typename?: 'Query', getWebUIUpdateSt
|
|||||||
export type GetServerSettingsQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetServerSettingsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetServerSettingsQuery = { __typename?: 'Query', settings: { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> } };
|
export type GetServerSettingsQuery = { __typename?: 'Query', settings: { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads: boolean, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, authMode: AuthMode, authPassword: string, authUsername: string, jwtAudience: string, jwtTokenExpiry: any, jwtRefreshExpiry: any, debugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean, opdsUseBinaryFileSizes: boolean, opdsItemsPerPage: number, opdsEnablePageReadProgress: boolean, opdsMarkAsReadOnDownload: boolean, opdsShowOnlyUnreadChapters: boolean, opdsShowOnlyDownloadedChapters: boolean, opdsChapterSortOrder: SortOrder, downloadConversions: Array<{ __typename?: 'SettingsDownloadConversionType', mimeType: string, target: string, compressionLevel?: number | null }> } };
|
||||||
|
|
||||||
export type GetSourceBrowseQueryVariables = Exact<{
|
export type GetSourceBrowseQueryVariables = Exact<{
|
||||||
id: Scalars['LongString']['input'];
|
id: Scalars['LongString']['input'];
|
||||||
|
|||||||
26
src/lib/graphql/mutations/UserMutation.ts
Normal file
26
src/lib/graphql/mutations/UserMutation.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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 gql from 'graphql-tag';
|
||||||
|
|
||||||
|
export const USER_LOGIN = gql`
|
||||||
|
mutation USER_LOGIN($password: String!, $username: String!) {
|
||||||
|
login(input: { password: $password, username: $username }) {
|
||||||
|
accessToken
|
||||||
|
refreshToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const USER_REFRESH = gql`
|
||||||
|
mutation USER_REFRESH($refreshToken: String!) {
|
||||||
|
refreshToken(input: { refreshToken: $refreshToken }) {
|
||||||
|
accessToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -212,6 +212,10 @@ import {
|
|||||||
GetExtensionQuery,
|
GetExtensionQuery,
|
||||||
GetExtensionQueryVariables,
|
GetExtensionQueryVariables,
|
||||||
DownloaderState,
|
DownloaderState,
|
||||||
|
UserLoginMutation,
|
||||||
|
UserLoginMutationVariables,
|
||||||
|
UserRefreshMutation,
|
||||||
|
UserRefreshMutationVariables,
|
||||||
} from '@/lib/graphql/generated/graphql.ts';
|
} from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts';
|
import { GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts';
|
||||||
import { DELETE_GLOBAL_METADATA, SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts';
|
import { DELETE_GLOBAL_METADATA, SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts';
|
||||||
@@ -327,6 +331,8 @@ import { CHAPTER_META_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts
|
|||||||
import { MetadataMigrationSettings } from '@/features/migration/Migration.types.ts';
|
import { MetadataMigrationSettings } from '@/features/migration/Migration.types.ts';
|
||||||
import { MangaIdInfo } from '@/features/manga/Manga.types.ts';
|
import { MangaIdInfo } from '@/features/manga/Manga.types.ts';
|
||||||
import { updateMetadataList } from '@/features/metadata/services/MetadataApolloCacheHandler.ts';
|
import { updateMetadataList } from '@/features/metadata/services/MetadataApolloCacheHandler.ts';
|
||||||
|
import { USER_LOGIN, USER_REFRESH } from '@/lib/graphql/mutations/UserMutation.ts';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
|
||||||
enum GQLMethod {
|
enum GQLMethod {
|
||||||
QUERY = 'QUERY',
|
QUERY = 'QUERY',
|
||||||
@@ -434,9 +440,9 @@ export const SPECIAL_ED_SOURCES = {
|
|||||||
export class RequestManager {
|
export class RequestManager {
|
||||||
public static readonly API_VERSION = '/api/v1/';
|
public static readonly API_VERSION = '/api/v1/';
|
||||||
|
|
||||||
public readonly graphQLClient = new GraphQLClient();
|
public readonly graphQLClient = new GraphQLClient(this.refreshUser.bind(this));
|
||||||
|
|
||||||
private readonly restClient: RestClient = new RestClient();
|
private readonly restClient: RestClient = new RestClient(this.refreshUser.bind(this));
|
||||||
|
|
||||||
private readonly cache = new CustomCache();
|
private readonly cache = new CustomCache();
|
||||||
|
|
||||||
@@ -452,6 +458,8 @@ export class RequestManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public reset(): void {
|
public reset(): void {
|
||||||
|
AuthManager.setAuthRequired(null);
|
||||||
|
AuthManager.removeTokens();
|
||||||
this.graphQLClient.client.resetStore();
|
this.graphQLClient.client.resetStore();
|
||||||
this.graphQLClient.terminateSubscriptions();
|
this.graphQLClient.terminateSubscriptions();
|
||||||
this.cache.clear();
|
this.cache.clear();
|
||||||
@@ -1020,7 +1028,7 @@ export class RequestManager {
|
|||||||
} = {},
|
} = {},
|
||||||
): ImageRequest {
|
): ImageRequest {
|
||||||
const finalOptions = {
|
const finalOptions = {
|
||||||
useFetchApi: false,
|
useFetchApi: AuthManager.isAuthRequired(),
|
||||||
shouldDecode: false,
|
shouldDecode: false,
|
||||||
disableCors: false,
|
disableCors: false,
|
||||||
...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined)),
|
...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined)),
|
||||||
@@ -3231,6 +3239,24 @@ export class RequestManager {
|
|||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public useLoginUser(
|
||||||
|
options?: MutationHookOptions<UserLoginMutation, UserLoginMutationVariables>,
|
||||||
|
): AbortableApolloUseMutationResponse<UserLoginMutation, UserLoginMutationVariables> {
|
||||||
|
return this.doRequest(GQLMethod.USE_MUTATION, USER_LOGIN, undefined, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public refreshUser(
|
||||||
|
refreshToken: string,
|
||||||
|
options?: MutationOptions<UserRefreshMutation, UserRefreshMutationVariables>,
|
||||||
|
): AbortableApolloMutationResponse<UserRefreshMutation> {
|
||||||
|
return this.doRequest<UserRefreshMutation, UserRefreshMutationVariables>(
|
||||||
|
GQLMethod.MUTATION,
|
||||||
|
USER_REFRESH,
|
||||||
|
{ refreshToken: refreshToken ?? undefined },
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const requestManager = new RequestManager();
|
export const requestManager = new RequestManager();
|
||||||
|
|||||||
@@ -7,12 +7,60 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AppStorage } from '@/lib/storage/AppStorage.ts';
|
import { AppStorage } from '@/lib/storage/AppStorage.ts';
|
||||||
|
import { UserRefreshMutation } from '@/lib/graphql/generated/graphql.ts';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
import { AbortableApolloMutationResponse } from '@/lib/requests/RequestManager.ts';
|
||||||
|
|
||||||
export abstract class BaseClient<Client, ClientConfig, Fetcher> {
|
export abstract class BaseClient<Client, ClientConfig, Fetcher> {
|
||||||
protected abstract client: Client;
|
protected abstract client: Client;
|
||||||
|
|
||||||
public abstract readonly fetcher: Fetcher;
|
public abstract readonly fetcher: Fetcher;
|
||||||
|
|
||||||
|
private static activeTokenRefreshPromise: Promise<UserRefreshMutation | null | undefined> | null = null;
|
||||||
|
|
||||||
|
protected static async refreshAccessToken(
|
||||||
|
refreshFn: (refreshToken: string) => AbortableApolloMutationResponse<UserRefreshMutation>,
|
||||||
|
): Promise<UserRefreshMutation | null | undefined> {
|
||||||
|
const refreshToken = AuthManager.getRefreshToken();
|
||||||
|
|
||||||
|
if (!AuthManager.isAuthRequired()) {
|
||||||
|
AuthManager.setAuthRequired(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!refreshToken) {
|
||||||
|
throw new Error('No refresh token found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.activeTokenRefreshPromise) {
|
||||||
|
return this.activeTokenRefreshPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshRequest = refreshFn(refreshToken).response;
|
||||||
|
this.activeTokenRefreshPromise = refreshRequest.then((result) => result.data);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await refreshRequest;
|
||||||
|
const { data } = result;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
throw new Error('No refreshed access token returned');
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthManager.setAccessToken(data.refreshToken.accessToken);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
AuthManager.removeTokens();
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
this.activeTokenRefreshPromise = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected constructor(
|
||||||
|
protected handleRefreshToken: (refreshToken: string) => AbortableApolloMutationResponse<UserRefreshMutation>,
|
||||||
|
) {}
|
||||||
|
|
||||||
public getBaseUrl(): string {
|
public getBaseUrl(): string {
|
||||||
const { hostname, port, protocol } = window.location;
|
const { hostname, port, protocol } = window.location;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { onError } from '@apollo/client/link/error';
|
||||||
|
import { setContext } from '@apollo/client/link/context';
|
||||||
import {
|
import {
|
||||||
ApolloClient,
|
ApolloClient,
|
||||||
ApolloClientOptions,
|
ApolloClientOptions,
|
||||||
@@ -14,6 +16,7 @@ import {
|
|||||||
NormalizedCacheObject,
|
NormalizedCacheObject,
|
||||||
split,
|
split,
|
||||||
from,
|
from,
|
||||||
|
fromPromise,
|
||||||
} from '@apollo/client';
|
} from '@apollo/client';
|
||||||
import createUploadLink from 'apollo-upload-client/createUploadLink.mjs';
|
import createUploadLink from 'apollo-upload-client/createUploadLink.mjs';
|
||||||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
||||||
@@ -23,6 +26,9 @@ import { TypePolicies } from '@apollo/client/cache';
|
|||||||
import { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';
|
import { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';
|
||||||
import { BaseClient } from '@/lib/requests/client/BaseClient.ts';
|
import { BaseClient } from '@/lib/requests/client/BaseClient.ts';
|
||||||
import { StrictTypedTypePolicies } from '@/lib/graphql/generated/apollo-helpers.ts';
|
import { StrictTypedTypePolicies } from '@/lib/graphql/generated/apollo-helpers.ts';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
import { UserRefreshMutation } from '@/lib/graphql/generated/graphql.ts';
|
||||||
|
import { AbortableApolloMutationResponse } from '@/lib/requests/RequestManager.ts';
|
||||||
|
|
||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
const typePolicies: StrictTypedTypePolicies = {
|
const typePolicies: StrictTypedTypePolicies = {
|
||||||
@@ -187,8 +193,8 @@ export class GraphQLClient extends BaseClient<
|
|||||||
|
|
||||||
private wsClient!: Client;
|
private wsClient!: Client;
|
||||||
|
|
||||||
constructor() {
|
constructor(handleRefreshToken: (refreshToken: string) => AbortableApolloMutationResponse<UserRefreshMutation>) {
|
||||||
super();
|
super(handleRefreshToken);
|
||||||
|
|
||||||
this.createClient();
|
this.createClient();
|
||||||
}
|
}
|
||||||
@@ -201,8 +207,44 @@ export class GraphQLClient extends BaseClient<
|
|||||||
this.wsClient.terminate();
|
this.wsClient.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createErrorLink() {
|
||||||
|
return onError(({ graphQLErrors, operation, forward }) => {
|
||||||
|
if (!graphQLErrors) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAuthError = graphQLErrors.some((graphQLError) =>
|
||||||
|
graphQLError.message.includes('suwayomi.tachidesk.server.user.UnauthorizedException'),
|
||||||
|
);
|
||||||
|
if (!isAuthError) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fromPromise(BaseClient.refreshAccessToken(this.handleRefreshToken))
|
||||||
|
.filter(Boolean)
|
||||||
|
.flatMap(() => forward(operation));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private createAuthLink() {
|
||||||
|
return setContext((_, { headers }) => {
|
||||||
|
const isAuthRequired = AuthManager.isAuthRequired();
|
||||||
|
const accessToken = AuthManager.getAccessToken();
|
||||||
|
|
||||||
|
return {
|
||||||
|
headers: {
|
||||||
|
credentials: 'include',
|
||||||
|
...headers,
|
||||||
|
Authorization: isAuthRequired && accessToken ? `Bearer ${accessToken}` : '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private createUploadLink() {
|
private createUploadLink() {
|
||||||
return createUploadLink({ uri: () => this.getBaseUrl(), credentials: 'include' });
|
return createUploadLink({
|
||||||
|
uri: () => this.getBaseUrl(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private createWSLink() {
|
private createWSLink() {
|
||||||
@@ -218,8 +260,13 @@ export class GraphQLClient extends BaseClient<
|
|||||||
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
|
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
|
||||||
},
|
},
|
||||||
this.createWSLink(),
|
this.createWSLink(),
|
||||||
// apollo-upload-client dependency is outdated (see 134e47763faae9e62db4d4e3a8387a74e32e5568) and thus types are not matching, but they are still correct
|
from([
|
||||||
from([removeTypenameLink, this.createUploadLink() as unknown as ApolloLink]),
|
this.createErrorLink(),
|
||||||
|
this.createAuthLink(),
|
||||||
|
removeTypenameLink,
|
||||||
|
// apollo-upload-client dependency is outdated (see 134e47763faae9e62db4d4e3a8387a74e32e5568) and thus types are not matching, but they are still correct
|
||||||
|
this.createUploadLink() as unknown as ApolloLink,
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,6 +277,14 @@ export class GraphQLClient extends BaseClient<
|
|||||||
url: () => this.getBaseUrl().replace(/http(|s)/g, 'ws'),
|
url: () => this.getBaseUrl().replace(/http(|s)/g, 'ws'),
|
||||||
keepAlive: heartbeatInterval,
|
keepAlive: heartbeatInterval,
|
||||||
retryAttempts: 10,
|
retryAttempts: 10,
|
||||||
|
connectionParams: () => {
|
||||||
|
const isAuthRequired = AuthManager.isAuthRequired();
|
||||||
|
const accessToken = AuthManager.getAccessToken();
|
||||||
|
|
||||||
|
return {
|
||||||
|
Authorization: isAuthRequired && accessToken ? accessToken : undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let lastHeartbeat: number = 0;
|
let lastHeartbeat: number = 0;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BaseClient } from '@/lib/requests/client/BaseClient.ts';
|
import { BaseClient } from '@/lib/requests/client/BaseClient.ts';
|
||||||
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
|
import { UserRefreshMutation } from '@/lib/graphql/generated/graphql.ts';
|
||||||
|
import { AbortableApolloMutationResponse } from '@/lib/requests/RequestManager.ts';
|
||||||
|
|
||||||
export enum HttpMethod {
|
export enum HttpMethod {
|
||||||
GET = 'GET',
|
GET = 'GET',
|
||||||
@@ -48,17 +51,28 @@ export class RestClient
|
|||||||
} = {},
|
} = {},
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
const updatedUrl = url.startsWith('http') ? url : `${this.getBaseUrl()}${url}`;
|
const updatedUrl = url.startsWith('http') ? url : `${this.getBaseUrl()}${url}`;
|
||||||
|
const accessToken = AuthManager.getAccessToken();
|
||||||
|
|
||||||
let result: Response;
|
let result: Response;
|
||||||
|
|
||||||
switch (httpMethod) {
|
switch (httpMethod) {
|
||||||
case HttpMethod.GET:
|
case HttpMethod.GET:
|
||||||
result = await this.client(updatedUrl, { ...this.config, ...config, method: httpMethod });
|
result = await this.client(updatedUrl, {
|
||||||
|
...this.config,
|
||||||
|
...config,
|
||||||
|
method: httpMethod,
|
||||||
|
headers: {
|
||||||
|
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
|
||||||
|
...this.config.headers,
|
||||||
|
...config?.headers,
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case HttpMethod.POST:
|
case HttpMethod.POST:
|
||||||
case HttpMethod.PATCH:
|
case HttpMethod.PATCH:
|
||||||
case HttpMethod.DELETE:
|
case HttpMethod.DELETE:
|
||||||
result = await this.client(updatedUrl, {
|
result = await this.client(updatedUrl, {
|
||||||
|
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
|
||||||
...this.config,
|
...this.config,
|
||||||
...config,
|
...config,
|
||||||
method: httpMethod,
|
method: httpMethod,
|
||||||
@@ -69,6 +83,11 @@ export class RestClient
|
|||||||
throw new Error(`Unexpected HttpMethod "${httpMethod}"`);
|
throw new Error(`Unexpected HttpMethod "${httpMethod}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.status === 401) {
|
||||||
|
await BaseClient.refreshAccessToken(this.handleRefreshToken);
|
||||||
|
return this.fetcher(url, { data, httpMethod, config, checkResponseIsJson });
|
||||||
|
}
|
||||||
|
|
||||||
if (result.status !== 200) {
|
if (result.status !== 200) {
|
||||||
throw new Error(`status ${result.status}: ${result.statusText}`);
|
throw new Error(`status ${result.status}: ${result.statusText}`);
|
||||||
}
|
}
|
||||||
@@ -80,8 +99,8 @@ export class RestClient
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor(handleRefreshToken: (refreshToken: string) => AbortableApolloMutationResponse<UserRefreshMutation>) {
|
||||||
super();
|
super(handleRefreshToken);
|
||||||
|
|
||||||
this.createClient();
|
this.createClient();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ const fixTypingOfQueryTypePolicies = format(
|
|||||||
\textension?: FieldPolicy<any> | FieldReadFunction<any>,
|
\textension?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\textensions?: FieldPolicy<any> | FieldReadFunction<any>,
|
\textensions?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\tgetWebUIUpdateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
\tgetWebUIUpdateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
\tkoSyncStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\tlastUpdateTimestamp?: FieldPolicy<any> | FieldReadFunction<any>,
|
\tlastUpdateTimestamp?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\tlibraryUpdateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
\tlibraryUpdateStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\tmanga?: FieldPolicy<any> | FieldReadFunction<any>,
|
\tmanga?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
@@ -93,6 +94,7 @@ const fixTypingOfQueryTypePolicies = format(
|
|||||||
\textension?: FieldPolicy<any> | FieldReadFunction<any>,
|
\textension?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\textensions?: FieldPolicy<any> | FieldReadFunction<any>,
|
\textensions?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\tgetWebUIUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>>,
|
\tgetWebUIUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetWebuiUpdateStatusQueryVariables>>,
|
||||||
|
\tkoSyncStatus?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\tlastUpdateTimestamp?: FieldPolicy<any> | FieldReadFunction<any>,
|
\tlastUpdateTimestamp?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
\tlibraryUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>>,
|
\tlibraryUpdateStatus?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetUpdateStatusQueryVariables>>,
|
||||||
\tmanga?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>>,
|
\tmanga?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetMangaScreenQueryVariables>>,
|
||||||
|
|||||||
10
yarn.lock
10
yarn.lock
@@ -2877,6 +2877,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/extract-files/-/extract-files-13.0.1.tgz#3ec057a3fa25f778245a76a17271d23b71ee31d7"
|
resolved "https://registry.yarnpkg.com/@types/extract-files/-/extract-files-13.0.1.tgz#3ec057a3fa25f778245a76a17271d23b71ee31d7"
|
||||||
integrity sha512-/fRbzc2lAd7jDJSSnxWiUyXWjdUZZ4HbISLJzVgt1AvrdOa7U49YRPcvuCUywkmURZ7uwJOheDjx19itbQ5KvA==
|
integrity sha512-/fRbzc2lAd7jDJSSnxWiUyXWjdUZZ4HbISLJzVgt1AvrdOa7U49YRPcvuCUywkmURZ7uwJOheDjx19itbQ5KvA==
|
||||||
|
|
||||||
|
"@types/js-cookie@^3.0.6":
|
||||||
|
version "3.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.6.tgz#a04ca19e877687bd449f5ad37d33b104b71fdf95"
|
||||||
|
integrity sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==
|
||||||
|
|
||||||
"@types/js-yaml@^4.0.0":
|
"@types/js-yaml@^4.0.0":
|
||||||
version "4.0.9"
|
version "4.0.9"
|
||||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2"
|
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2"
|
||||||
@@ -6513,6 +6518,11 @@ jpeg-js@^0.4.4:
|
|||||||
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa"
|
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa"
|
||||||
integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==
|
integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==
|
||||||
|
|
||||||
|
js-cookie@^3.0.5:
|
||||||
|
version "3.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
|
||||||
|
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
|
||||||
|
|
||||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
|||||||
Reference in New Issue
Block a user