Compare commits

...

4 Commits

Author SHA1 Message Date
358c9b511a Added JobStatusView
Individual Jobs can now be cancelled
2023-09-08 19:59:12 +02:00
f791d1f977 Added Ping behaviour and loader circle.
When opening website, check will run wether api is reachable
2023-09-08 16:32:48 +02:00
37e2a74c39 Added loader-circle 2023-09-08 16:32:09 +02:00
fc546e68cc Added API Ping function 2023-09-08 16:31:55 +02:00
4 changed files with 283 additions and 29 deletions

View File

@ -51,6 +51,11 @@ function DeleteData(uri){
}); });
} }
async function Ping(){
let ret = await GetData(`${apiUri}/Ping`);
return ret;
}
async function GetAvailableControllers(){ async function GetAvailableControllers(){
var uri = apiUri + "/Connectors"; var uri = apiUri + "/Connectors";
let json = await GetData(uri); let json = await GetData(uri);

View File

@ -20,6 +20,11 @@
<img id="settingscog" src="media/settings-cogwheel.svg" height="100%" alt="settingscog"> <img id="settingscog" src="media/settings-cogwheel.svg" height="100%" alt="settingscog">
</topbar> </topbar>
<viewport> <viewport>
<div id="loaderdiv">
<blur-background></blur-background>
<div id="loader"></div>
<p id="loaderText">Check your Settings > API-URI</p>
</div>
<content> <content>
<div id="addPublication"> <div id="addPublication">
<p>+</p> <p>+</p>
@ -109,6 +114,18 @@
</publication-information> </publication-information>
</publication-viewer> </publication-viewer>
</popup> </popup>
<popup id="jobStatusView">
<blur-background id="blurBackgroundJobStatus" onclick="jobStatusView.style.display= 'none';"></blur-background>
<popup-window>
<div>
<div id="jobStatusRunning" style="border-right: 1px solid gray;"></div>
</div>
<div>
<div id="jobStatusWaiting" style="border-left: 1px solid gray;"></div>
</div>
</popup-window>
</popup>
</viewport> </viewport>
<footer> <footer>

View File

@ -1,4 +1,5 @@
let jobs = []; let runningJobs = [];
let waitingJobs = [];
let notificationConnectorTypes = []; let notificationConnectorTypes = [];
let libraryConnectorTypes = []; let libraryConnectorTypes = [];
let selectedManga; let selectedManga;
@ -41,28 +42,40 @@ const newMangaTitle = document.querySelector("#newMangaTitle");
const newMangaResult = document.querySelector("#newMangaResult"); const newMangaResult = document.querySelector("#newMangaResult");
const jobsRunningTag = document.querySelector("#jobsRunningTag"); const jobsRunningTag = document.querySelector("#jobsRunningTag");
const jobsQueuedTag = document.querySelector("#jobsQueuedTag"); const jobsQueuedTag = document.querySelector("#jobsQueuedTag");
const loaderdiv = document.querySelector('#loaderdiv');
const jobStatusView = document.querySelector("#jobStatusView");
const jobStatusRunning = document.querySelector("#jobStatusRunning");
const jobStatusWaiting = document.querySelector("#jobStatusWaiting");
function Setup(){ function Setup(){
GetAvailableNotificationConnectors().then((json) => { Ping().then((ret) => {
json.forEach(connector => { loaderdiv.style.display = 'none';
notificationConnectorTypes[connector.Key] = connector.Value;
GetAvailableNotificationConnectors().then((json) => {
json.forEach(connector => {
notificationConnectorTypes[connector.Key] = connector.Value;
});
}); });
});
GetAvailableLibraryConnectors().then((json) => { GetAvailableLibraryConnectors().then((json) => {
json.forEach(connector => { json.forEach(connector => {
libraryConnectorTypes[connector.Key] = connector.Value; libraryConnectorTypes[connector.Key] = connector.Value;
});
}); });
});
GetAvailableControllers().then((json) => {
GetAvailableControllers().then((json) => { json.forEach(connector => {
json.forEach(connector => { var option = document.createElement('option');
var option = document.createElement('option'); option.value = connector;
option.value = connector; option.innerText = connector;
option.innerText = connector; newMangaConnector.appendChild(option);
newMangaConnector.appendChild(option); });
}); });
UpdateJobs();
setInterval(() => {
UpdateJobs();
}, 1000);
}); });
} }
Setup(); Setup();
@ -115,7 +128,7 @@ function GetNewMangaItems(){
//Returns a new "Publication" Item to display in the jobs section //Returns a new "Publication" Item to display in the jobs section
function CreateManga(manga, connector){ function CreateManga(manga, connector){
var mangaElement = document.createElement('publication'); var mangaElement = document.createElement('publication');
mangaElement.setAttribute("id", manga.internalId); mangaElement.id = GetValidSelector(manga.internalId);
var mangaImage = document.createElement('img'); var mangaImage = document.createElement('img');
mangaImage.src = GetCoverUrl(manga.internalId); mangaImage.src = GetCoverUrl(manga.internalId);
mangaElement.appendChild(mangaImage); mangaElement.appendChild(mangaImage);
@ -331,17 +344,13 @@ function UpdateSettings(){
} }
OpenSettings(); OpenSettings();
Setup();
} }
function utf8_to_b64(str) { function utf8_to_b64(str) {
return window.btoa(unescape(encodeURIComponent( str ))); return window.btoa(unescape(encodeURIComponent( str )));
} }
UpdateJobs();
setInterval(() => {
UpdateJobs();
}, 1000);
function UpdateJobs(){ function UpdateJobs(){
GetMonitorJobs().then((json) => { GetMonitorJobs().then((json) => {
ResetContent(); ResetContent();
@ -354,16 +363,120 @@ function UpdateJobs(){
tasksContent.appendChild(mangaView); tasksContent.appendChild(mangaView);
}); });
}); });
GetWaitingJobs().then((json) => {
jobsQueuedTag.innerText = json.length;
var nowWaitingJobs = [];
json.forEach(job => {
if(!waitingJobs.includes(GetValidSelector(job.id))){
var jobDom = createJob(job);
jobStatusWaiting.appendChild(jobDom);
}
nowWaitingJobs.push(GetValidSelector(job.id));
});
waitingJobs = nowWaitingJobs;
});
jobStatusWaiting.childNodes.forEach(child => {
if(!waitingJobs.includes(child.id))
jobStatusWaiting.removeChild(child);
});
GetRunningJobs().then((json) => { GetRunningJobs().then((json) => {
console.log("Running");
console.log(json);
jobsRunningTag.innerText = json.length; jobsRunningTag.innerText = json.length;
var nowRunningJobs = [];
json.forEach(job => {
if(!runningJobs.includes(GetValidSelector(job.id))){
var jobDom = createJob(job);
jobStatusRunning.appendChild(jobDom);
}
nowRunningJobs.push(GetValidSelector(job.id));
UpdateJobProgress(job.id);
});
runningJobs = nowRunningJobs;
}); });
GetWaitingJobs().then((json) => { jobStatusRunning.childNodes.forEach(child => {
console.log("Waiting"); if(!runningJobs.includes(child.id))
console.log(json); jobStatusRunning.removeChild(child);
jobsQueuedTag.innerText = json.length;
}); });
} }
function createJob(jobjson){
var manga;
if(jobjson.chapter != null)
manga = jobjson.chapter.parentManga;
else if(jobjson.manga != null)
manga = jobjson.manga;
else return null;
var wrapper = document.createElement("div");
wrapper.className = "jobWrapper";
wrapper.id = GetValidSelector(jobjson.id);
var image = document.createElement("img");
image.className = "jobImage";
image.src = GetCoverUrl(manga.internalId);
wrapper.appendChild(image);
var title = document.createElement("span");
title.className = "jobTitle";
if(jobjson.chapter != null)
title.innerText = `${manga.sortName} - ${jobjson.chapter.fileName}`;
else if(jobjson.manga != null)
title.innerText = manga.sortName;
wrapper.appendChild(title);
var progressBar = document.createElement("progress");
progressBar.className = "jobProgressBar";
progressBar.id = `jobProgressBar${GetValidSelector(jobjson.id)}`;
wrapper.appendChild(progressBar);
var progressSpan = document.createElement("span");
progressSpan.className = "jobProgressSpan";
progressSpan.id = `jobProgressSpan${GetValidSelector(jobjson.id)}`;
progressSpan.innerText = "0% 00:00:00";
wrapper.appendChild(progressSpan);
var cancelSpan = document.createElement("span");
cancelSpan.className = "jobCancel";
cancelSpan.innerText = "Cancel";
cancelSpan.addEventListener("click", () => CancelJob(jobjson.id));
wrapper.appendChild(cancelSpan);
return wrapper;
}
function ShowJobQueue(){
jobStatusView.style.display = "initial";
}
function UpdateJobProgress(jobId){
GetProgress(jobId).then((json) => {
var progressBar = document.querySelector(`#jobProgressBar${GetValidSelector(jobId)}`);
var progressSpan = document.querySelector(`#jobProgressSpan${GetValidSelector(jobId)}`);
if(progressBar != null && json.progress != 0){
progressBar.value = json.progress;
}
if(progressSpan != null){
var percentageStr = "0%";
var timeleftStr = "00:00:00";
if(json.progress != 0){
percentageStr = Intl.NumberFormat("en-US", { style: "percent"}).format(json.progress);
timeleftStr = json.timeRemaining.split('.')[0];
}
progressSpan.innerText = `${percentageStr} ${timeleftStr}`;
}
});
}
function GetValidSelector(str){
var clean = [...str.matchAll(/[a-zA-Z0-9]*-*_*/g)];
return clean.join('');
}

View File

@ -148,7 +148,7 @@ content {
} }
#settingsPopup{ #settingsPopup{
z-index: 10; z-index: 300;
} }
#settingsPopup popup-content{ #settingsPopup popup-content{
@ -507,4 +507,123 @@ footer-tag-popup::before{
left: 0; left: 0;
bottom: -17px; bottom: -17px;
border-radius: 0 0 0 5px; border-radius: 0 0 0 5px;
}
#loaderdiv {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 200;
}
#loader {
border: 16px solid transparent;
border-top: 16px solid var(--secondary-color);
border-bottom: 16px solid var(--primary-color);
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
position: absolute;
left: calc(50% - 60px);
top: calc(50% - 120px);
z-index: 201;
}
#loaderText {
position: relative;
margin: 0 auto;
top: calc(50% + 80px);
z-index: 201;
text-align: center;
color: var(--second-background-color);
font-size: 20pt;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#jobStatusView {
z-index: 50;
}
#jobStatusView > popup-window {
top: 80px;
width: 50%;
max-height: calc(100% - 140px);
display: flex;
flex-direction: row;
flex-wrap: nowrap;
background-color: transparent;
}
#jobStatusView > popup-window > div {
overflow-y: scroll;
overflow-x: hidden;
width: 50%;
margin: 0;
max-height: 100%;
}
#jobStatusView > popup-window > div > div {
overflow-x: hidden;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
width: 100%;
margin: 0;
}
.jobWrapper {
width: 90%;
margin: 2px 5%;
height: 100px;
position: relative;
flex-shrink: 0;
background-color: rgba(187,187,187,0.4);
border-radius: 3px;
}
.jobWrapper > .jobImage {
height: 90%;
width: 20%;
left: 5px;
object-fit: contain;
position: absolute;
top: 5%;
}
.jobWrapper > .jobTitle {
position: absolute;
left: calc(20% + 10px);
top: 5px;
}
.jobWrapper > .jobProgressBar {
position: absolute;
left: calc(20% + 10px);
bottom: calc(12pt + 10px);
width: calc(80% - 20px);
height: 10px;
}
.jobWrapper > .jobProgressSpan {
position: absolute;
right: 10px;
bottom: calc(12pt + 20px);
width: 60%;
text-align: right;
}
.jobWrapper > .jobCancel {
position: absolute;
right: 10px;
bottom: 5px;
font-size: 12pt;
color: var(--secondary-color);
cursor: pointer;
} }