Rewrite AddInstanceFlow
Now with spinner!
This commit is contained in:
parent
2be0658ed9
commit
bfd61c2e50
6 changed files with 144 additions and 58 deletions
|
@ -1,14 +1,27 @@
|
|||
import { AddInstanceDialog } from "./add_an_instance.mjs";
|
||||
import { initializeInstanceDetailsDialog } from "./confirm_instance_details.mjs";
|
||||
import { Dialog } from "./dialog.mjs";
|
||||
import storageManager, { Instance } from "./storage_manager.mjs";
|
||||
|
||||
export function initializeAddInstanceFlow(
|
||||
export class AddInstanceFlow {
|
||||
addDialog: AddInstanceDialog;
|
||||
spinnerDialog: Dialog;
|
||||
detailsDialog: HTMLDialogElement;
|
||||
|
||||
constructor(
|
||||
addDialog: AddInstanceDialog | HTMLDialogElement,
|
||||
spinnerDialog: HTMLDialogElement,
|
||||
detailsDialog: HTMLDialogElement,
|
||||
addDialog: HTMLDialogElement
|
||||
): {
|
||||
showAddInstanceDialog: () => void,
|
||||
hideAddInstanceDialog: () => void
|
||||
} {
|
||||
) {
|
||||
if (addDialog instanceof AddInstanceDialog)
|
||||
this.addDialog = addDialog;
|
||||
else
|
||||
this.addDialog = new AddInstanceDialog(addDialog, true);
|
||||
this.spinnerDialog = new Dialog(spinnerDialog);
|
||||
this.detailsDialog = detailsDialog;
|
||||
}
|
||||
|
||||
async start() {
|
||||
const instanceDetailsDialogCallback = (
|
||||
name: string,
|
||||
host: string,
|
||||
|
@ -31,39 +44,35 @@ export function initializeAddInstanceFlow(
|
|||
showInstanceDetailsDialog,
|
||||
hideInstanceDetailsDialog,
|
||||
populateInstanceDetailsDialog
|
||||
} = initializeInstanceDetailsDialog(detailsDialog, instanceDetailsDialogCallback);
|
||||
} = initializeInstanceDetailsDialog(this.detailsDialog, instanceDetailsDialogCallback);
|
||||
|
||||
const {
|
||||
autoQueryMetadata,
|
||||
host,
|
||||
secure,
|
||||
} = await this.addDialog.prompt();
|
||||
|
||||
const addInstanceDialogCallback = async (
|
||||
host: string,
|
||||
secure: boolean,
|
||||
autoQueryMetadata: boolean,
|
||||
) => {
|
||||
try {
|
||||
if (!autoQueryMetadata) throw new Error("Don't");
|
||||
if (!autoQueryMetadata) throw null; // Skip to catch block
|
||||
|
||||
this.spinnerDialog.open();
|
||||
|
||||
const { name, software, iconURL } =
|
||||
await fetch(`/api/instance_info/${secure}/${encodeURIComponent(host)}`)
|
||||
.then(r => r.json());
|
||||
if (
|
||||
typeof name !== "string"
|
||||
|| typeof software !== "string"
|
||||
|| !(typeof iconURL === "string" || iconURL === null)
|
||||
|| !(typeof iconURL === "string" || iconURL === null) // I guess TS is too stupid to understand this?
|
||||
)
|
||||
throw new Error("Invalid API response");
|
||||
|
||||
populateInstanceDetailsDialog(name, host, secure, software, iconURL as string | null);
|
||||
} catch {
|
||||
populateInstanceDetailsDialog(host, host, secure, "", null);
|
||||
} finally {
|
||||
this.spinnerDialog.close();
|
||||
showInstanceDetailsDialog();
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
showAddInstanceDialog,
|
||||
hideAddInstanceDialog
|
||||
} = initializeAddInstanceDialog(addDialog, addInstanceDialogCallback);
|
||||
|
||||
return {
|
||||
showAddInstanceDialog,
|
||||
hideAddInstanceDialog
|
||||
};
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<p id="no-instance">You currently don't have any instances. You should add one!</p>
|
||||
<form id="instanceSelectForm" class="align-start wfit-content"></form>
|
||||
<br>
|
||||
<button id="showAddInstanceDialog">Add an instance</button>
|
||||
<button id="startAddInstanceFlow">Add an instance</button>
|
||||
</center>
|
||||
</div>
|
||||
<div class="half-width align-self-start">
|
||||
|
@ -108,6 +108,7 @@ Unchecking this is not recommended, and this option only exists for exceptional
|
|||
<button type="reset" class="close">Cancel</button>
|
||||
</form>
|
||||
</dialog>
|
||||
<dialog id="spinner"><span class="spinner"></span></dialog>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,20 +1,22 @@
|
|||
import { initializeAddInstanceFlow } from "./add_instance_flow.mjs";
|
||||
import { AddInstanceFlow } from "./add_instance_flow.mjs";
|
||||
import { findButtonOrFail, findDialogOrFail, findFormOrFail, findInputOrFail, findParagraphOrFail, findPreOrFail } from "./dom.mjs";
|
||||
import knownSoftware from "./known_software.mjs";
|
||||
import storageManager from "./storage_manager.mjs";
|
||||
|
||||
const radioButtonName = "instanceSelect";
|
||||
|
||||
let addInstanceFlow: AddInstanceFlow | undefined;
|
||||
const mainDialog = findDialogOrFail(document.body, "#mainDialog");
|
||||
const showAddInstanceDialogButton = findButtonOrFail(document.body, "#showAddInstanceDialog");
|
||||
const detailsDialog = findDialogOrFail(document.body, "#instanceDetails");
|
||||
const startAddInstanceFlowButton = findButtonOrFail(document.body, "#startAddInstanceFlow");
|
||||
const addDialog = findDialogOrFail(document.body, "#addInstance");
|
||||
const spinnerDialog = findDialogOrFail(document.body, "#spinner");
|
||||
const detailsDialog = findDialogOrFail(document.body, "#instanceDetails");
|
||||
const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm");
|
||||
const redirectButton = findButtonOrFail(document.body, "#redirect");
|
||||
const redirectAlwaysButton = findButtonOrFail(document.body, "#redirectAlways");
|
||||
const pathText = findPreOrFail(document.body, "#path");
|
||||
|
||||
showAddInstanceDialogButton.addEventListener("click", e => showAddInstanceDialog());
|
||||
startAddInstanceFlowButton.addEventListener("click", e => addInstanceFlow?.start());
|
||||
|
||||
redirectButton.addEventListener("click", e => {
|
||||
// Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default
|
||||
|
@ -28,9 +30,6 @@ redirectAlwaysButton.addEventListener("click", e => {
|
|||
redirect(option);
|
||||
});
|
||||
|
||||
let showAddInstanceDialog = () => { };
|
||||
let hideAddInstanceDialog = () => { };
|
||||
|
||||
// Don't bother initializing if we're performing autoredirect
|
||||
if (!autoRedirect()) {
|
||||
createInstanceSelectOptions();
|
||||
|
@ -40,10 +39,7 @@ if (!autoRedirect()) {
|
|||
|
||||
pathText.innerText = getTargetPath();
|
||||
|
||||
({
|
||||
showAddInstanceDialog,
|
||||
hideAddInstanceDialog
|
||||
} = initializeAddInstanceFlow(detailsDialog, addDialog));
|
||||
addInstanceFlow = new AddInstanceFlow(addDialog, spinnerDialog, detailsDialog);
|
||||
|
||||
mainDialog.show();
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ export class Dialog {
|
|||
*/
|
||||
protected initializeDOM() { }
|
||||
|
||||
protected open() {
|
||||
open() {
|
||||
this.dialog.showModal();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@import url("/static/spinner.css");
|
||||
|
||||
:root {
|
||||
--red: #cb0b0b;
|
||||
--blue: #2081c3;
|
||||
|
|
78
static/spinner.css
Normal file
78
static/spinner.css
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* Sourced and modified from https://cssloaders.github.io/ */
|
||||
|
||||
.spinner {
|
||||
display: block;
|
||||
animation: rotate 1s infinite;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.spinner:before,
|
||||
.spinner:after {
|
||||
border-radius: 50%;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.spinner:before {
|
||||
animation: ball1 1s infinite;
|
||||
background-color: var(--red);
|
||||
box-shadow: 30px 0 0 var(--blue);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.spinner:after {
|
||||
animation: ball2 1s infinite;
|
||||
background-color: var(--blue);
|
||||
box-shadow: 30px 0 0 var(--red);
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
0% {
|
||||
transform: rotate(0deg) scale(0.8)
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(360deg) scale(1.2)
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(720deg) scale(0.8)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ball1 {
|
||||
0% {
|
||||
box-shadow: 30px 0 0 var(--blue);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 0 var(--blue);
|
||||
margin-bottom: 0;
|
||||
transform: translate(15px, 15px);
|
||||
}
|
||||
|
||||
100% {
|
||||
box-shadow: 30px 0 0 var(--blue);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ball2 {
|
||||
0% {
|
||||
box-shadow: 30px 0 0 var(--red);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 0 var(--red);
|
||||
margin-top: -20px;
|
||||
transform: translate(15px, 15px);
|
||||
}
|
||||
|
||||
100% {
|
||||
box-shadow: 30px 0 0 var(--red);
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue