mirror of
https://github.com/tachiyomiorg/tachiyomi-extensions-inspector.git
synced 2024-12-25 00:01:49 +01:00
better messages, axios client
This commit is contained in:
parent
954084bd82
commit
7157e07328
@ -8,6 +8,7 @@
|
|||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
|
"axios": "^0.21.1",
|
||||||
"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",
|
||||||
|
@ -18,7 +18,7 @@ export default function Extensions() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (extensions.length === 0) {
|
if (extensions.length === 0) {
|
||||||
return <h3>wait</h3>;
|
return <h3>loading...</h3>;
|
||||||
}
|
}
|
||||||
return <>{extensions.map((it) => <ExtensionCard extension={it} />)}</>;
|
return <>{extensions.map((it) => <ExtensionCard extension={it} />)}</>;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,12 @@ import { Tab, Tabs } from '@material-ui/core';
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import MangaGrid from '../components/MangaGrid';
|
import MangaGrid from '../components/MangaGrid';
|
||||||
import NavBarTitle from '../context/NavbarTitle';
|
import NavBarTitle from '../context/NavbarTitle';
|
||||||
|
import client from '../util/client';
|
||||||
|
|
||||||
interface IMangaCategory {
|
interface IMangaCategory {
|
||||||
category: ICategory
|
category: ICategory
|
||||||
mangas: IManga[]
|
mangas: IManga[]
|
||||||
|
isFetched: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TabPanelProps {
|
interface TabPanelProps {
|
||||||
@ -46,66 +48,62 @@ export default function Library() {
|
|||||||
setTitle('Library');
|
setTitle('Library');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleTabChange = (newTab: number) => {
|
||||||
|
setTabNum(newTab);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Promise.all<IManga[], ICategory[]>([
|
||||||
|
client.get('/api/v1/library').then((response) => response.data),
|
||||||
|
client.get('/api/v1/category').then((response) => response.data),
|
||||||
|
])
|
||||||
|
.then(
|
||||||
|
([libraryMangas, categories]) => {
|
||||||
|
const categoryTabs = categories.map((category) => ({
|
||||||
|
category,
|
||||||
|
mangas: [] as IManga[],
|
||||||
|
isFetched: false,
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (libraryMangas.length > 0 || categoryTabs.length === 0) {
|
||||||
|
const defaultCategoryTab = {
|
||||||
|
category: {
|
||||||
|
name: 'Default',
|
||||||
|
isLanding: true,
|
||||||
|
order: 0,
|
||||||
|
id: -1,
|
||||||
|
},
|
||||||
|
mangas: libraryMangas,
|
||||||
|
isFetched: true,
|
||||||
|
};
|
||||||
|
setTabs(
|
||||||
|
[defaultCategoryTab, ...categoryTabs],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setTabs(categoryTabs);
|
||||||
|
setTabNum(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// fetch the current tab
|
||||||
|
useEffect(() => {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.category.order === tabNum && !tab.isFetched) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||||
const fetchAndSetMangas = (tabs: IMangaCategory[], tab: IMangaCategory, index: number) => {
|
|
||||||
fetch(`http://127.0.0.1:4567/api/v1/category/${tab.category.id}`)
|
fetch(`http://127.0.0.1:4567/api/v1/category/${tab.category.id}`)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data: IManga[]) => {
|
.then((data: IManga[]) => {
|
||||||
const tabsClone = JSON.parse(JSON.stringify(tabs));
|
const tabsClone = JSON.parse(JSON.stringify(tabs));
|
||||||
tabsClone[index].mangas = data;
|
tabsClone[index].mangas = data;
|
||||||
|
tabsClone[index].isFetched = true;
|
||||||
|
|
||||||
setTabs(tabsClone); // clone the object
|
setTabs(tabsClone); // clone the object
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const handleTabChange = (newTab: number) => {
|
|
||||||
setTabNum(newTab);
|
|
||||||
tabs.forEach((tab, index) => {
|
|
||||||
if (tab.category.order === newTab && tab.mangas.length === 0) {
|
|
||||||
// mangas are empty, fetch the mangas
|
|
||||||
fetchAndSetMangas(tabs, tab, index);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}, [tabNum]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetch('http://127.0.0.1:4567/api/v1/library')
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((data: IManga[]) => {
|
|
||||||
// if some manga with no category exist, they will be added under a virtual category
|
|
||||||
if (data.length > 0) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
category: {
|
|
||||||
name: 'Default', isLanding: true, order: 0, id: -1,
|
|
||||||
},
|
|
||||||
mangas: data,
|
|
||||||
},
|
|
||||||
]; // will set state on the next fetch
|
|
||||||
}
|
|
||||||
|
|
||||||
// no default category so the first tab is 1
|
|
||||||
setTabNum(1);
|
|
||||||
return [];
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
(newTabs: IMangaCategory[]) => {
|
|
||||||
fetch('http://127.0.0.1:4567/api/v1/category')
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((data: ICategory[]) => {
|
|
||||||
const mangaCategories = data.map((category) => ({
|
|
||||||
category,
|
|
||||||
mangas: [] as IManga[],
|
|
||||||
}));
|
|
||||||
const newNewTabs = [...newTabs, ...mangaCategories];
|
|
||||||
setTabs(newNewTabs);
|
|
||||||
|
|
||||||
// if no default category, we must fetch the first tab now...
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
if (newTabs.length === 0) { fetchAndSetMangas(newNewTabs, newNewTabs[0], 0); }
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
let toRender;
|
let toRender;
|
||||||
if (tabs.length > 1) {
|
if (tabs.length > 1) {
|
||||||
@ -119,6 +117,7 @@ export default function Library() {
|
|||||||
hasNextPage={false}
|
hasNextPage={false}
|
||||||
lastPageNum={lastPageNum}
|
lastPageNum={lastPageNum}
|
||||||
setLastPageNum={setLastPageNum}
|
setLastPageNum={setLastPageNum}
|
||||||
|
message={tab.isFetched ? 'Category is Empty' : 'Loading...'}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
));
|
));
|
||||||
@ -149,6 +148,7 @@ export default function Library() {
|
|||||||
hasNextPage={false}
|
hasNextPage={false}
|
||||||
lastPageNum={lastPageNum}
|
lastPageNum={lastPageNum}
|
||||||
setLastPageNum={setLastPageNum}
|
setLastPageNum={setLastPageNum}
|
||||||
|
message={tabs.length > 0 ? 'Library is Empty' : undefined}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,17 @@ export default function Sources() {
|
|||||||
const { setTitle } = useContext(NavBarTitle);
|
const { setTitle } = useContext(NavBarTitle);
|
||||||
setTitle('Sources');
|
setTitle('Sources');
|
||||||
const [sources, setSources] = useState<ISource[]>([]);
|
const [sources, setSources] = useState<ISource[]>([]);
|
||||||
|
const [fetched, setFetched] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch('http://127.0.0.1:4567/api/v1/source/list')
|
fetch('http://127.0.0.1:4567/api/v1/source/list')
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => setSources(data));
|
.then((data) => { setSources(data); setFetched(true); });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (sources.length === 0) {
|
if (sources.length === 0) {
|
||||||
return (<h3>wait</h3>);
|
if (fetched) return (<h3>No sources found. Install Some Extensions first.</h3>);
|
||||||
|
return (<h3>loading...</h3>);
|
||||||
}
|
}
|
||||||
return <>{sources.map((it) => <SourceCard source={it} />)}</>;
|
return <>{sources.map((it) => <SourceCard source={it} />)}</>;
|
||||||
}
|
}
|
||||||
|
10
webUI/react/src/util/client.tsx
Normal file
10
webUI/react/src/util/client.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import storage from './storage';
|
||||||
|
|
||||||
|
const clientMaker = () => axios.create({
|
||||||
|
baseURL: storage.getItem('baseURL', 'http://127.0.0.1:4567'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const client = clientMaker();
|
||||||
|
|
||||||
|
export default client;
|
22
webUI/react/src/util/storage.tsx
Normal file
22
webUI/react/src/util/storage.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
function getItem<T>(key: string, defaultValue: T) : T {
|
||||||
|
try {
|
||||||
|
const item = window.localStorage.getItem(key);
|
||||||
|
|
||||||
|
if (item !== null) { return JSON.parse(item); }
|
||||||
|
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(defaultValue));
|
||||||
|
} finally {
|
||||||
|
// eslint-disable-next-line no-unsafe-finally
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setItem<T>(key: string, value: T): void {
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(value));
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-empty
|
||||||
|
} catch (error) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { getItem, setItem };
|
@ -2625,6 +2625,13 @@ axe-core@^4.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.1.tgz#70a7855888e287f7add66002211a423937063eaf"
|
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.1.tgz#70a7855888e287f7add66002211a423937063eaf"
|
||||||
integrity sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==
|
integrity sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==
|
||||||
|
|
||||||
|
axios@^0.21.1:
|
||||||
|
version "0.21.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||||
|
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.10.0"
|
||||||
|
|
||||||
axobject-query@^2.2.0:
|
axobject-query@^2.2.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
|
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
|
||||||
@ -5233,6 +5240,11 @@ follow-redirects@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||||
|
|
||||||
|
follow-redirects@^1.10.0:
|
||||||
|
version "1.13.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
|
||||||
|
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
|
||||||
|
|
||||||
fontsource-roboto@^4.0.0:
|
fontsource-roboto@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fontsource-roboto/-/fontsource-roboto-4.0.0.tgz#35eacd4fb8d90199053c0eec9b34a57fb79cd820"
|
resolved "https://registry.yarnpkg.com/fontsource-roboto/-/fontsource-roboto-4.0.0.tgz#35eacd4fb8d90199053c0eec9b34a57fb79cd820"
|
||||||
|
Loading…
Reference in New Issue
Block a user