diff --git a/static/add_an_instance.mts b/static/add_an_instance.mts index e305637..5503dc1 100644 --- a/static/add_an_instance.mts +++ b/static/add_an_instance.mts @@ -10,7 +10,14 @@ export function parseHost(host: string): { host: string, secure: boolean } | nul }; } -export function initializeAddInstanceDialog(dialog: HTMLDialogElement): { +export function initializeAddInstanceDialog( + dialog: HTMLDialogElement, + callback: ( + host: string, + secure: boolean, + autoQueryMetadata: boolean, + ) => void +): { showAddInstanceDialog: () => void, hideAddInstanceDialog: () => void, } { @@ -32,12 +39,14 @@ export function initializeAddInstanceDialog(dialog: HTMLDialogElement): { instanceHost.setCustomValidity(""); }); - form.addEventListener("submit", async e => { + const autoQueryMetadata = form.querySelector("#autoQueryMetadata"); + if (!(autoQueryMetadata instanceof HTMLInputElement)) + throw new Error("#autoQueryMetadata isn't an input"); + + form.addEventListener("submit", e => { // A sane browser doesn't allow for submitting the form if the above validation fails const { host, secure } = parseHost(instanceHost.value)!; - console.log( - await fetch(`/api/instance_info/${secure}/${encodeURI(host)}`).then(r => r.json()) - ); + callback(host, secure, autoQueryMetadata.checked); form.reset(); }); diff --git a/static/confirm_instance_details.mts b/static/confirm_instance_details.mts new file mode 100644 index 0000000..0a19609 --- /dev/null +++ b/static/confirm_instance_details.mts @@ -0,0 +1,70 @@ +// This file handles the "Confirm instance details" dialog + +import knownSoftware from "./known_software.mjs"; + +const blankImage = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + +export function initializeInstanceDetailsDialog(dialog: HTMLDialogElement): { + showInstanceDetailsDialog: () => void, + hideInstanceDetailsDialog: () => void, + populateInstanceDetailsDialog: ( + instanceNameValue: string, + instanceSoftwareValue: string, + instanceIconValue: string | null + ) => void, +} { + const showInstanceDetailsDialog = () => dialog.showModal(); + const hideInstanceDetailsDialog = () => dialog.close(); + + const form = dialog.querySelector(".instanceDetailsForm"); + if (!(form instanceof HTMLFormElement)) + throw new Error(".instanceDetailsForm isn't a form"); + + const instanceName = form.querySelector("#instanceName"); + if (!(instanceName instanceof HTMLInputElement)) + throw new Error("#instanceName isn't an input"); + + const instanceSoftware = form.querySelector("#instanceSoftware"); + if (!(instanceSoftware instanceof HTMLSelectElement)) + throw new Error("#instanceSoftware isn't a select"); + + for (const [name, software] of Object.entries(knownSoftware.software)) { + const option = new Option(software.name, name); + instanceSoftware.appendChild(option); + } + + const instanceIcon = form.querySelector("#instanceIcon"); + if (!(instanceIcon instanceof HTMLImageElement)) + throw new Error("#instanceIcon isn't an image"); + + instanceIcon.src = blankImage; + + const populateInstanceDetailsDialog = ( + instanceNameValue: string, + instanceSoftwareValue: string, + instanceIconValue: string | null + ) => { + instanceName.value = instanceNameValue; + instanceSoftware.value = instanceSoftwareValue; + instanceIcon.src = instanceIconValue ?? blankImage; + }; + + form.addEventListener("submit", e => { + form.reset(); + }); + + const closeButton = form.querySelector(".close"); + if (!(closeButton instanceof HTMLButtonElement)) + throw new Error(".close isn't a button"); + + closeButton.addEventListener("click", e => { + instanceIcon.src = blankImage; + hideInstanceDetailsDialog(); + }); + + return { + showInstanceDetailsDialog, + hideInstanceDetailsDialog, + populateInstanceDetailsDialog + }; +} diff --git a/static/crossroad.css b/static/crossroad.css index a390c14..92bcd3c 100644 --- a/static/crossroad.css +++ b/static/crossroad.css @@ -1,6 +1,7 @@ :root { --red: #cb0b0b; --blue: #2081c3; + --transparent-black: #0008; --large: 2em; --medium: 1em; } @@ -25,7 +26,7 @@ dialog { dialog::backdrop { backdrop-filter: blur(5px); - background-color: #0008; + background-color: var(--transparent-black); transition: background-color 0.125s ease-out; @starting-style { @@ -65,6 +66,16 @@ abbr[title] { flex-direction: row; } +.flex-row-reverse { + display: flex; + flex-direction: row-reverse; +} + +.flex-column-reverse { + display: flex; + flex-direction: column-reverse; +} + .half-width { min-width: 50%; } @@ -73,8 +84,12 @@ abbr[title] { min-height: 50%; } +.full-height { + min-height: 100%; +} + .separator-bottom { - border-bottom: solid 1px #0008; + border-bottom: solid 1px var(--transparent-black); } .margin-auto-top { @@ -83,4 +98,25 @@ abbr[title] { .margin-large-bottom { margin-bottom: var(--large); +} + +.square { + aspect-ratio: 1; +} + +.iconContainer { + width: 64px; + height: 64px; + padding: 1px; + border: solid 1px var(--transparent-black); +} + +.icon { + position: relative; + max-width: 64px; + max-height: 64px; + margin: auto; + top: 50%; + left: 50%; + translate: -50% -50%; } \ No newline at end of file diff --git a/static/crossroad.html b/static/crossroad.html index 405032e..7dd8312 100644 --- a/static/crossroad.html +++ b/static/crossroad.html @@ -58,6 +58,38 @@ We do not track or save any requests or data."> Cancel + + Confirm instance details + + + + Instance name + + + + Instance software + + + (Please select) + + + + + + Instance icon + + + + + + + + + + OK + Cancel + +