mirror of
https://github.com/tachiyomiorg/tachiyomi-extensions-inspector.git
synced 2025-02-13 15:19:15 +01:00
front-end UI done
This commit is contained in:
parent
0c79f207c3
commit
455a35f8ae
@ -192,7 +192,6 @@ object LegacyBackupImport : LegacyBackupBase() {
|
|||||||
it[status] = fetchedManga.status
|
it[status] = fetchedManga.status
|
||||||
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url!!.isNotEmpty())
|
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url!!.isNotEmpty())
|
||||||
it[MangaTable.thumbnail_url] = fetchedManga.thumbnail_url
|
it[MangaTable.thumbnail_url] = fetchedManga.thumbnail_url
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ import kotlinx.coroutines.SupervisorJob
|
|||||||
import kotlinx.coroutines.future.future
|
import kotlinx.coroutines.future.future
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -326,7 +328,7 @@ object JavalinSetup {
|
|||||||
ctx.json(getCategoryMangaList(categoryId))
|
ctx.json(getCategoryMangaList(categoryId))
|
||||||
}
|
}
|
||||||
|
|
||||||
// expects a Tachiyomi legacy backup json to be uploaded
|
// expects a Tachiyomi legacy backup json in the body
|
||||||
app.post("/api/v1/backup/legacy/import") { ctx ->
|
app.post("/api/v1/backup/legacy/import") { ctx ->
|
||||||
ctx.result(
|
ctx.result(
|
||||||
future {
|
future {
|
||||||
@ -335,7 +337,16 @@ object JavalinSetup {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns a Tachiyomi legacy backup json created from the current database
|
// expects a Tachiyomi legacy backup json as a file upload, the file must be named "backup.json"
|
||||||
|
app.post("/api/v1/backup/legacy/import/file") { ctx ->
|
||||||
|
ctx.result(
|
||||||
|
future {
|
||||||
|
restoreLegacyBackup(ctx.uploadedFile("backup.json")!!.content)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a Tachiyomi legacy backup json created from the current database as a json body
|
||||||
app.get("/api/v1/backup/legacy/export") { ctx ->
|
app.get("/api/v1/backup/legacy/export") { ctx ->
|
||||||
ctx.contentType("application/json")
|
ctx.contentType("application/json")
|
||||||
ctx.result(
|
ctx.result(
|
||||||
@ -352,5 +363,27 @@ object JavalinSetup {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns a Tachiyomi legacy backup json created from the current database as a file
|
||||||
|
app.get("/api/v1/backup/legacy/export/file") { ctx ->
|
||||||
|
ctx.contentType("application/json")
|
||||||
|
val sdf = SimpleDateFormat("yyyy-MM-dd_HH-mm")
|
||||||
|
val currentDate = sdf.format(Date())
|
||||||
|
|
||||||
|
ctx.header("Content-Disposition", "attachment; filename=\"tachidesk_$currentDate.json\"")
|
||||||
|
ctx.result(
|
||||||
|
future {
|
||||||
|
createLegacyBackup(
|
||||||
|
BackupFlags(
|
||||||
|
includeManga = true,
|
||||||
|
includeCategories = true,
|
||||||
|
includeChapters = true,
|
||||||
|
includeTracking = true,
|
||||||
|
includeHistory = true,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
"@types/react-lazyload": "^3.1.0",
|
"@types/react-lazyload": "^3.1.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
|
"file-selector": "^0.2.4",
|
||||||
"fontsource-roboto": "^4.0.0",
|
"fontsource-roboto": "^4.0.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-beautiful-dnd": "^13.0.0",
|
"react-beautiful-dnd": "^13.0.0",
|
||||||
|
@ -25,6 +25,7 @@ import DarkTheme from './context/DarkTheme';
|
|||||||
import Library from './screens/Library';
|
import Library from './screens/Library';
|
||||||
import Settings from './screens/Settings';
|
import Settings from './screens/Settings';
|
||||||
import Categories from './screens/settings/Categories';
|
import Categories from './screens/settings/Categories';
|
||||||
|
import Backup from './screens/settings/Backup';
|
||||||
import useLocalStorage from './util/useLocalStorage';
|
import useLocalStorage from './util/useLocalStorage';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@ -103,6 +104,9 @@ export default function App() {
|
|||||||
<Route path="/settings/categories">
|
<Route path="/settings/categories">
|
||||||
<Categories />
|
<Categories />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route path="/settings/backup">
|
||||||
|
<Backup />
|
||||||
|
</Route>
|
||||||
<Route path="/settings">
|
<Route path="/settings">
|
||||||
<DarkTheme.Provider value={darkThemeContext}>
|
<DarkTheme.Provider value={darkThemeContext}>
|
||||||
<Settings />
|
<Settings />
|
||||||
|
@ -16,15 +16,11 @@ import {
|
|||||||
DialogContentText, IconButton, ListItemSecondaryAction, Switch, TextField,
|
DialogContentText, IconButton, ListItemSecondaryAction, Switch, TextField,
|
||||||
ListItemIcon, ListItemText,
|
ListItemIcon, ListItemText,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import ListItem, { ListItemProps } from '@material-ui/core/ListItem';
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
import NavbarContext from '../context/NavbarContext';
|
import NavbarContext from '../context/NavbarContext';
|
||||||
import DarkTheme from '../context/DarkTheme';
|
import DarkTheme from '../context/DarkTheme';
|
||||||
import useLocalStorage from '../util/useLocalStorage';
|
import useLocalStorage from '../util/useLocalStorage';
|
||||||
|
import ListItemLink from '../util/ListItemLink';
|
||||||
function ListItemLink(props: ListItemProps<'a', { button?: true }>) {
|
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
||||||
return <ListItem button component="a" {...props} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const { setTitle, setAction } = useContext(NavbarContext);
|
const { setTitle, setAction } = useContext(NavbarContext);
|
||||||
@ -58,6 +54,12 @@ export default function Settings() {
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Categories" />
|
<ListItemText primary="Categories" />
|
||||||
</ListItemLink>
|
</ListItemLink>
|
||||||
|
<ListItemLink href="/settings/backup">
|
||||||
|
<ListItemIcon>
|
||||||
|
<InboxIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary="Backup" />
|
||||||
|
</ListItemLink>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Brightness6Icon />
|
<Brightness6Icon />
|
||||||
|
91
webUI/react/src/screens/settings/Backup.tsx
Normal file
91
webUI/react/src/screens/settings/Backup.tsx
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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 React, { useContext, useEffect } from 'react';
|
||||||
|
import { ListItemIcon } from '@material-ui/core';
|
||||||
|
import List from '@material-ui/core/List';
|
||||||
|
import InboxIcon from '@material-ui/icons/Inbox';
|
||||||
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
|
import { fromEvent } from 'file-selector';
|
||||||
|
import ListItemLink from '../../util/ListItemLink';
|
||||||
|
import NavbarContext from '../../context/NavbarContext';
|
||||||
|
import client from '../../util/client';
|
||||||
|
|
||||||
|
export default function Backup() {
|
||||||
|
const { setTitle, setAction } = useContext(NavbarContext);
|
||||||
|
useEffect(() => { setTitle('Backup'); setAction(<></>); }, []);
|
||||||
|
|
||||||
|
const { baseURL } = client.defaults;
|
||||||
|
|
||||||
|
const submitBackup = (file: File) => {
|
||||||
|
file.text()
|
||||||
|
.then(
|
||||||
|
(fileContent: string) => {
|
||||||
|
client.post('/api/v1/backup/legacy/import',
|
||||||
|
fileContent, { headers: { 'Content-Type': 'application/json' } });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dropHandler = async (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const files = await fromEvent(e);
|
||||||
|
|
||||||
|
submitBackup(files[0] as File);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dragOverHandler = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.addEventListener('drop', dropHandler);
|
||||||
|
document.addEventListener('dragover', dragOverHandler);
|
||||||
|
|
||||||
|
const input = document.getElementById('backup-file');
|
||||||
|
input?.addEventListener('change', async (evt) => {
|
||||||
|
const files = await fromEvent(evt);
|
||||||
|
submitBackup(files[0] as File);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('drop', dropHandler);
|
||||||
|
document.removeEventListener('dragover', dragOverHandler);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List style={{ padding: 0 }}>
|
||||||
|
<ListItemLink href={`${baseURL}/api/v1/backup/legacy/export/file`}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<InboxIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="Create Legacy Backup"
|
||||||
|
secondary="Backup library as a Tachiyomi legacy backup"
|
||||||
|
/>
|
||||||
|
</ListItemLink>
|
||||||
|
<ListItem button onClick={() => document.getElementById('backup-file')?.click()}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<InboxIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="Restore Legacy Backup"
|
||||||
|
secondary="You can also drop the backup file anywhere to restore"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
name="backup.json"
|
||||||
|
id="backup-file"
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
14
webUI/react/src/util/ListItemLink.tsx
Normal file
14
webUI/react/src/util/ListItemLink.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* 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 React from 'react';
|
||||||
|
import ListItem, { ListItemProps } from '@material-ui/core/ListItem';
|
||||||
|
|
||||||
|
export default function ListItemLink(props: ListItemProps<'a', { button?: true }>) {
|
||||||
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
|
return <ListItem button component="a" {...props} />;
|
||||||
|
}
|
@ -5136,6 +5136,13 @@ file-loader@6.1.1:
|
|||||||
loader-utils "^2.0.0"
|
loader-utils "^2.0.0"
|
||||||
schema-utils "^3.0.0"
|
schema-utils "^3.0.0"
|
||||||
|
|
||||||
|
file-selector@^0.2.4:
|
||||||
|
version "0.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80"
|
||||||
|
integrity sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.3"
|
||||||
|
|
||||||
file-uri-to-path@1.0.0:
|
file-uri-to-path@1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user