mirror of
https://github.com/C9Glax/tranga-website.git
synced 2025-06-13 15:27:53 +02:00
Add auto-update when adding/removing Manga
Style SearchResults
This commit is contained in:
@ -9,7 +9,9 @@ export class Job
|
||||
return getData("http://127.0.0.1:6531/v2/Jobs")
|
||||
.then((json) => {
|
||||
console.debug("Got all Jobs");
|
||||
return (json as string[]);
|
||||
const ret = json as string[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -18,7 +20,9 @@ export class Job
|
||||
return getData("http://127.0.0.1:6531/v2/Jobs/Running")
|
||||
.then((json) => {
|
||||
console.debug("Got all running Jobs");
|
||||
return (json as string[]);
|
||||
const ret = json as string[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -27,7 +31,9 @@ export class Job
|
||||
return getData("http://127.0.0.1:6531/v2/Jobs/Waiting")
|
||||
.then((json) => {
|
||||
console.debug("Got all waiting Jobs");
|
||||
return (json as string[]);
|
||||
const ret = json as string[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -36,7 +42,9 @@ export class Job
|
||||
return getData("http://127.0.0.1:6531/v2/Jobs/Monitoring")
|
||||
.then((json) => {
|
||||
console.debug("Got all monitoring Jobs");
|
||||
return (json as string[]);
|
||||
const ret = json as string[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -49,7 +57,9 @@ export class Job
|
||||
return getData(`http://127.0.0.1:6531/v2/Job/${jobId}`)
|
||||
.then((json) => {
|
||||
console.debug(`Got Job ${jobId}`);
|
||||
return (json as IJob);
|
||||
const ret = json as IJob;
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -63,7 +73,9 @@ export class Job
|
||||
return getData(`http://127.0.0.1:6531/v2/Job?jobIds=${reqStr}`)
|
||||
.then((json) => {
|
||||
console.debug(`Got Jobs ${reqStr}`);
|
||||
return (json as IJob[]);
|
||||
const ret = json as IJob[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -72,11 +84,13 @@ export class Job
|
||||
return getData(`http://127.0.0.1:6531/v2/Job/${jobId}/Progress`)
|
||||
.then((json) => {
|
||||
console.debug(`Got Job ${jobId} Progress`);
|
||||
return (json as IProgressToken);
|
||||
const ret = json as IProgressToken;
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
static async CreateJob(internalId: string, jobType: string, interval: string): Promise<IJob> {
|
||||
static async CreateJob(internalId: string, jobType: string, interval: string): Promise<null> {
|
||||
console.debug(`Creating Job for Manga ${internalId} at ${interval} interval`);
|
||||
let data = {
|
||||
internalId: internalId,
|
||||
@ -85,19 +99,19 @@ export class Job
|
||||
return postData(`http://127.0.0.1:6531/v2/Job/Create/${jobType}`, data)
|
||||
.then((json) => {
|
||||
console.debug(`Created Job for Manga ${internalId} at ${interval} interval`);
|
||||
return (json as IJob);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
static DeleteJob(jobId: string) {
|
||||
deleteData(`http://127.0.0.1:6531/v2/Job/${jobId}`);
|
||||
static DeleteJob(jobId: string) : Promise<void> {
|
||||
return deleteData(`http://127.0.0.1:6531/v2/Job/${jobId}`);
|
||||
}
|
||||
|
||||
static StartJob(jobId: string) {
|
||||
postData(`http://127.0.0.1:6531/v2/Job/${jobId}/StartNow`, {});
|
||||
static StartJob(jobId: string) : Promise<object> {
|
||||
return postData(`http://127.0.0.1:6531/v2/Job/${jobId}/StartNow`, {});
|
||||
}
|
||||
|
||||
static CancelJob(jobId: string) {
|
||||
postData(`http://127.0.0.1:6531/v2/Job/${jobId}/Cancel`, {});
|
||||
static CancelJob(jobId: string) : Promise<object> {
|
||||
return postData(`http://127.0.0.1:6531/v2/Job/${jobId}/Cancel`, {});
|
||||
}
|
||||
}
|
@ -8,7 +8,9 @@ export class Manga
|
||||
return getData("http://127.0.0.1:6531/v2/Mangas")
|
||||
.then((json) => {
|
||||
console.debug("Got all Manga");
|
||||
return (json as IManga[]);
|
||||
const ret = json as IManga[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -17,7 +19,9 @@ export class Manga
|
||||
return await getData(`http://127.0.0.1:6531/v2/Manga/Search?title=${name}`)
|
||||
.then((json) => {
|
||||
console.debug(`Got Manga ${name}`);
|
||||
return (json as IManga[]);
|
||||
const ret = json as IManga[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -26,7 +30,9 @@ export class Manga
|
||||
return await getData(`http://127.0.0.1:6531/v2/Manga/${internalId}`)
|
||||
.then((json) => {
|
||||
console.debug(`Got Manga ${internalId}`);
|
||||
return (json as IManga);
|
||||
const ret = json as IManga;
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
@ -35,7 +41,9 @@ export class Manga
|
||||
return await getData(`http://127.0.0.1:6531/v2/Manga?internalIds=${internalIds.join(",")}`)
|
||||
.then((json) => {
|
||||
console.debug(`Got Manga ${internalIds.join(",")}`);
|
||||
return (json as IManga[]);
|
||||
const ret = json as IManga[];
|
||||
console.debug(ret);
|
||||
return (ret);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,17 @@
|
||||
import React, {MouseEventHandler, ReactElement, useEffect} from 'react';
|
||||
import React, {EventHandler, MouseEventHandler, ReactElement, useEffect, useState} from 'react';
|
||||
import {Job} from './Job';
|
||||
import '../styles/monitorMangaList.css';
|
||||
import IJob from "./interfaces/IJob";
|
||||
import IManga, {HTMLFromIManga} from "./interfaces/IManga";
|
||||
import IManga, {CoverCard} from "./interfaces/IManga";
|
||||
import {Manga} from './Manga';
|
||||
import '../styles/MangaCoverCard.css'
|
||||
|
||||
export default function MonitorJobsList({onStartSearch} : {onStartSearch() : void}){
|
||||
const [MonitoringJobs, setMonitoringJobs] = React.useState<IJob[]>([]);
|
||||
const [AllManga, setAllManga] = React.useState<IManga[]>([]);
|
||||
|
||||
function UpdateMonitoringJobsList(){
|
||||
Job.GetMonitoringJobs()
|
||||
.then((jobs) => {
|
||||
if(jobs.length > 0)
|
||||
return Job.GetJobs(jobs)
|
||||
return [];
|
||||
})
|
||||
.then((jobs) => setMonitoringJobs(jobs));
|
||||
}
|
||||
export default function MonitorJobsList({onStartSearch, onJobsChanged} : {onStartSearch() : void, onJobsChanged: EventHandler<any>}) {
|
||||
const [MonitoringJobs, setMonitoringJobs] = useState<IJob[]>([]);
|
||||
const [AllManga, setAllManga] = useState<IManga[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
console.debug("Updating display list.");
|
||||
//Remove all Manga that are not associated with a Job
|
||||
setAllManga(AllManga.filter(manga => MonitoringJobs.find(job => job.mangaInternalId == manga.internalId)));
|
||||
//Fetch Manga that are missing (from Jobs)
|
||||
@ -36,9 +28,20 @@ export default function MonitorJobsList({onStartSearch} : {onStartSearch() : voi
|
||||
UpdateMonitoringJobsList();
|
||||
}, []);
|
||||
|
||||
const DeleteJob:MouseEventHandler = (e) => {
|
||||
const DeleteJob : MouseEventHandler = (e) => {
|
||||
const jobId = e.currentTarget.id;
|
||||
Job.DeleteJob(jobId);
|
||||
Job.DeleteJob(jobId).then(() => onJobsChanged(jobId));
|
||||
}
|
||||
|
||||
function UpdateMonitoringJobsList(){
|
||||
console.debug("Updating MonitoringJobsList");
|
||||
Job.GetMonitoringJobs()
|
||||
.then((jobs) => {
|
||||
if(jobs.length > 0)
|
||||
return Job.GetJobs(jobs)
|
||||
return [];
|
||||
})
|
||||
.then((jobs) => setMonitoringJobs(jobs));
|
||||
}
|
||||
|
||||
function StartSearchMangaEntry() : ReactElement {
|
||||
@ -61,7 +64,7 @@ export default function MonitorJobsList({onStartSearch} : {onStartSearch() : voi
|
||||
if (job === undefined || job == null)
|
||||
return <div>Error. Could not find matching job for {manga.internalId}</div>
|
||||
return <div key={"monitorMangaEntry." + manga.internalId} className="monitorMangaEntry">
|
||||
{HTMLFromIManga(manga)}
|
||||
{CoverCard(manga)}
|
||||
{job.id}
|
||||
<button id={job.id} onClick={DeleteJob}>Delete</button>
|
||||
</div>;
|
||||
|
@ -1,12 +1,13 @@
|
||||
import React, { ChangeEventHandler, MouseEventHandler, useEffect, useState} from 'react';
|
||||
import React, {ChangeEventHandler, EventHandler, MouseEventHandler, useEffect, useState} from 'react';
|
||||
import {MangaConnector} from "./MangaConnector";
|
||||
import {Job} from "./Job";
|
||||
import IMangaConnector from "./interfaces/IMangaConnector";
|
||||
import {isValidUri} from "../App";
|
||||
import IManga, {HTMLFromIManga} from "./interfaces/IManga";
|
||||
import IManga, {SearchResult} from "./interfaces/IManga";
|
||||
import '../styles/search.css';
|
||||
import '../styles/MangaSearchResult.css'
|
||||
|
||||
export default function Search(){
|
||||
export default function Search({onJobsChanged} : {onJobsChanged: EventHandler<any>}) {
|
||||
const [mangaConnectors, setConnectors] = useState<IMangaConnector[]>();
|
||||
const [selectedConnector, setSelectedConnector] = useState<IMangaConnector>();
|
||||
const [selectedLanguage, setSelectedLanguage] = useState<string>();
|
||||
@ -88,28 +89,25 @@ export default function Search(){
|
||||
|
||||
return (<div>
|
||||
<div id="SearchBox">
|
||||
<input type="text" placeholder="Manganame" onChange={searchBoxValueChanged}></input>
|
||||
<select value={selectedConnector === undefined ? "" : selectedConnector.name} onChange={selectedConnectorChanged}>
|
||||
<input type="text" placeholder="Manganame" id="Searchbox-Manganame" onChange={searchBoxValueChanged}></input>
|
||||
<select id="Searchbox-Connector" value={selectedConnector === undefined ? "" : selectedConnector.name} onChange={selectedConnectorChanged}>
|
||||
<option value="" disabled hidden>Select</option>
|
||||
{mangaConnectors === undefined
|
||||
? <option value="Loading">Loading</option>
|
||||
: mangaConnectors.map(con => <option value={con.name} key={con.name}>{con.name}</option>)}
|
||||
</select>
|
||||
<select onChange={changeSelectedLanguage} value={selectedLanguage === null ? "" : selectedLanguage}>
|
||||
<select id="Searchbox-language" onChange={changeSelectedLanguage} value={selectedLanguage === null ? "" : selectedLanguage}>
|
||||
{selectedConnector === undefined
|
||||
? <option value="" disabled hidden>Select Connector</option>
|
||||
: selectedConnector.SupportedLanguages.map(language => <option value={language}
|
||||
key={language}>{language}</option>)}
|
||||
</select>
|
||||
<button type="submit" onClick={ExecuteSearch}>Search</button>
|
||||
<button id="Searchbox-button" type="submit" onClick={ExecuteSearch}>Search</button>
|
||||
</div>
|
||||
<div>
|
||||
<div id="SearchResults">
|
||||
{searchResults === undefined
|
||||
? <p>No Results yet</p>
|
||||
: searchResults.map(result => <div key={"searchResult."+result.internalId} className="searchResult">
|
||||
{HTMLFromIManga(result)}
|
||||
<button onClick={(e) => {Job.CreateJob(result.internalId, "MonitorManga", "03:00:00")}}>Monitor</button>
|
||||
</div>)}
|
||||
? <p></p>
|
||||
: searchResults.map(result => SearchResult(result, onJobsChanged))}
|
||||
</div>
|
||||
</div>)
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
import IMangaConnector from "./IMangaConnector";
|
||||
import KeyValuePair from "./KeyValuePair";
|
||||
import {Manga} from "../Manga";
|
||||
import {ReactElement} from "react";
|
||||
import React, {ChangeEventHandler, EventHandler, ReactElement} from "react";
|
||||
import {Job} from "../Job";
|
||||
import Icon from '@mdi/react';
|
||||
import { mdiTagTextOutline, mdiAccountEdit } from '@mdi/js';
|
||||
|
||||
export default interface IManga{
|
||||
"sortName": string,
|
||||
@ -36,7 +39,7 @@ function ReleaseStatusFromNumber(n: number): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
export function HTMLFromIManga(manga: IManga) : ReactElement {
|
||||
export function CoverCard(manga: IManga) : ReactElement {
|
||||
return(
|
||||
<div className="Manga" key={manga.internalId}>
|
||||
<img src={Manga.GetMangaCoverUrl(manga.internalId)}></img>
|
||||
@ -46,4 +49,23 @@ export function HTMLFromIManga(manga: IManga) : ReactElement {
|
||||
<p className="Manga-name">{manga.sortName}</p>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
export function SearchResult(manga: IManga, jobsChanged: EventHandler<any>) : ReactElement {
|
||||
return(
|
||||
<div className="SearchResult" key={manga.internalId}>
|
||||
<img src={Manga.GetMangaCoverUrl(manga.internalId)}></img>
|
||||
<p className="connector-name">{manga.mangaConnector.name}</p>
|
||||
<div className="Manga-status" release-status={ReleaseStatusFromNumber(manga.releaseStatus)}></div>
|
||||
<p className="Manga-name">{manga.sortName}</p>
|
||||
<ul className="Manga-tags">
|
||||
{manga.authors.map(author => <li className="Manga-author" key={manga.internalId + "-author-" + author}> <Icon path={mdiAccountEdit} size={0.5} /> {author}</li>)}
|
||||
{manga.tags.map(tag => <li className="Manga-tag" key={manga.internalId + "-tag-" + tag}><Icon path={mdiTagTextOutline} size={0.5} /> {tag}</li>)}
|
||||
</ul>
|
||||
<p className="Manga-description">{manga.description}</p>
|
||||
<button className="Manga-AddButton" onClick={(e) => {
|
||||
Job.CreateJob(manga.internalId, "MonitorManga", "03:00:00").then(() => jobsChanged(manga.internalId));
|
||||
}}>Monitor
|
||||
</button>
|
||||
</div>);
|
||||
}
|
Reference in New Issue
Block a user