front-end UI done

This commit is contained in:
Aria Moradi 2021-04-10 00:44:13 +04:30
parent 0c79f207c3
commit 455a35f8ae
8 changed files with 160 additions and 9 deletions

View File

@ -192,7 +192,6 @@ object LegacyBackupImport : LegacyBackupBase() {
it[status] = fetchedManga.status
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url!!.isNotEmpty())
it[MangaTable.thumbnail_url] = fetchedManga.thumbnail_url
}
}

View File

@ -40,6 +40,8 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.future.future
import mu.KotlinLogging
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.concurrent.CompletableFuture
/*
@ -326,7 +328,7 @@ object JavalinSetup {
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 ->
ctx.result(
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 ->
ctx.contentType("application/json")
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,
)
)
}
)
}
}
}

View File

@ -10,6 +10,7 @@
"@testing-library/user-event": "^12.1.10",
"@types/react-lazyload": "^3.1.0",
"axios": "^0.21.1",
"file-selector": "^0.2.4",
"fontsource-roboto": "^4.0.0",
"react": "^17.0.1",
"react-beautiful-dnd": "^13.0.0",

View File

@ -25,6 +25,7 @@ import DarkTheme from './context/DarkTheme';
import Library from './screens/Library';
import Settings from './screens/Settings';
import Categories from './screens/settings/Categories';
import Backup from './screens/settings/Backup';
import useLocalStorage from './util/useLocalStorage';
export default function App() {
@ -103,6 +104,9 @@ export default function App() {
<Route path="/settings/categories">
<Categories />
</Route>
<Route path="/settings/backup">
<Backup />
</Route>
<Route path="/settings">
<DarkTheme.Provider value={darkThemeContext}>
<Settings />

View File

@ -16,15 +16,11 @@ import {
DialogContentText, IconButton, ListItemSecondaryAction, Switch, TextField,
ListItemIcon, ListItemText,
} 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 DarkTheme from '../context/DarkTheme';
import useLocalStorage from '../util/useLocalStorage';
function ListItemLink(props: ListItemProps<'a', { button?: true }>) {
// eslint-disable-next-line react/jsx-props-no-spreading
return <ListItem button component="a" {...props} />;
}
import ListItemLink from '../util/ListItemLink';
export default function Settings() {
const { setTitle, setAction } = useContext(NavbarContext);
@ -58,6 +54,12 @@ export default function Settings() {
</ListItemIcon>
<ListItemText primary="Categories" />
</ListItemLink>
<ListItemLink href="/settings/backup">
<ListItemIcon>
<InboxIcon />
</ListItemIcon>
<ListItemText primary="Backup" />
</ListItemLink>
<ListItem>
<ListItemIcon>
<Brightness6Icon />

View 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>
);
}

View 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} />;
}

View File

@ -5136,6 +5136,13 @@ file-loader@6.1.1:
loader-utils "^2.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:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"