This commit is contained in:
parent
bc7e388f04
commit
027faf8371
4 changed files with 138 additions and 29 deletions
|
@ -30,7 +30,17 @@
|
||||||
instance.<br>
|
instance.<br>
|
||||||
<img src="/static/down_arrow.svg" alt="" class="medium-height" />
|
<img src="/static/down_arrow.svg" alt="" class="medium-height" />
|
||||||
<p id="noInstance">You currently don't have any instances. You should add one!</p>
|
<p id="noInstance">You currently don't have any instances. You should add one!</p>
|
||||||
<form id="instanceSelectForm" class="align-start wfit-content"></form>
|
<form id="instanceSelectForm" class="align-start wfit-content">
|
||||||
|
<ol id="preferredList" class="margin-none" hidden></ol>
|
||||||
|
<div id="forks" hidden>
|
||||||
|
<p class="align-center margin-none-bottom">Other <span id="forkOf"></span> forks</p>
|
||||||
|
<ol id="forksList" class="margin-none"></ol>
|
||||||
|
</div>
|
||||||
|
<div id="others" hidden>
|
||||||
|
<p class="align-center margin-none-bottom">Other instances</p>
|
||||||
|
<ol id="othersList" class="margin-none"></ol>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
<br>
|
<br>
|
||||||
<button id="startAddInstanceFlow">Add an instance</button>
|
<button id="startAddInstanceFlow">Add an instance</button>
|
||||||
</center>
|
</center>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { AddInstanceFlow } from "./add_instance_flow.mjs";
|
import { AddInstanceFlow } from "./add_instance_flow.mjs";
|
||||||
import { findButtonOrFail, findDialogOrFail, findFormOrFail, findInputOrFail, findParagraphOrFail, findPreOrFail, findSpanOrFail } from "./dom.mjs";
|
import { findButtonOrFail, findDialogOrFail, findDivOrFail, findFormOrFail, findInputOrFail, findOlOrFail, findParagraphOrFail, findPreOrFail, findSpanOrFail } from "./dom.mjs";
|
||||||
import knownSoftware, { getName } from "./known_software.mjs";
|
import knownSoftware, { getName } from "./known_software.mjs";
|
||||||
import storageManager from "./storage_manager.mjs";
|
import storageManager, { Instance } from "./storage_manager.mjs";
|
||||||
|
|
||||||
const RADIO_BUTTON_NAME = "instanceSelect";
|
const RADIO_BUTTON_NAME = "instanceSelect";
|
||||||
|
|
||||||
|
@ -13,6 +13,12 @@ const addDialog = findDialogOrFail(document.body, "#addInstance");
|
||||||
const spinnerDialog = findDialogOrFail(document.body, "#spinner");
|
const spinnerDialog = findDialogOrFail(document.body, "#spinner");
|
||||||
const detailsDialog = findDialogOrFail(document.body, "#instanceDetails");
|
const detailsDialog = findDialogOrFail(document.body, "#instanceDetails");
|
||||||
const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm");
|
const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm");
|
||||||
|
const preferredList = findOlOrFail(document.body, "#preferredList");
|
||||||
|
const forksDiv = findDivOrFail(document.body, "#forks");
|
||||||
|
const forkOfSpan = findSpanOrFail(document.body, "#forkOf");
|
||||||
|
const forksList = findOlOrFail(document.body, "#forksList");
|
||||||
|
const othersDiv = findDivOrFail(document.body, "#others");
|
||||||
|
const othersList = findOlOrFail(document.body, "#othersList");
|
||||||
const redirectButton = findButtonOrFail(document.body, "#redirect");
|
const redirectButton = findButtonOrFail(document.body, "#redirect");
|
||||||
const redirectAlwaysButton = findButtonOrFail(document.body, "#redirectAlways");
|
const redirectAlwaysButton = findButtonOrFail(document.body, "#redirectAlways");
|
||||||
const noInstanceParagraph = findParagraphOrFail(document.body, "#noInstance");
|
const noInstanceParagraph = findParagraphOrFail(document.body, "#noInstance");
|
||||||
|
@ -58,9 +64,60 @@ function updateNoInstanceHint() {
|
||||||
storageManager.storage.instances.length > 0;
|
storageManager.storage.instances.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createInstanceSelectOptions() {
|
type PreferenceGroups = {
|
||||||
instanceSelectForm.replaceChildren(); // Erase all child nodes
|
preferred: Instance[],
|
||||||
|
forks?: {
|
||||||
|
list: Instance[],
|
||||||
|
of: string,
|
||||||
|
},
|
||||||
|
others: Instance[],
|
||||||
|
};
|
||||||
|
|
||||||
|
function sortInstancesIntoPreferenceGroups(): PreferenceGroups {
|
||||||
|
const targetID = getTargetSoftwareOrGroup();
|
||||||
|
const pGroups: PreferenceGroups = {
|
||||||
|
preferred: [],
|
||||||
|
others: [],
|
||||||
|
};
|
||||||
|
// If targetID is a group
|
||||||
|
if (knownSoftware.groups[targetID]) {
|
||||||
for (const instance of storageManager.storage.instances) {
|
for (const instance of storageManager.storage.instances) {
|
||||||
|
const software = knownSoftware.software[instance.software];
|
||||||
|
// If the instance's software is in the target group
|
||||||
|
if (software.groups.includes(targetID)) {
|
||||||
|
pGroups.preferred.push(instance);
|
||||||
|
} else {
|
||||||
|
pGroups.others.push(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const isFork = knownSoftware.software[targetID].forkOf !== undefined;
|
||||||
|
const forkOf = knownSoftware.software[targetID].forkOf ?? targetID;
|
||||||
|
const hasForks = isFork || Object.values(knownSoftware.software).some(s => s.forkOf === forkOf);
|
||||||
|
if (hasForks) {
|
||||||
|
pGroups.forks = {
|
||||||
|
list: [],
|
||||||
|
of: forkOf,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (const instance of storageManager.storage.instances) {
|
||||||
|
if (instance.software === targetID) {
|
||||||
|
pGroups.preferred.push(instance);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const software = knownSoftware.software[instance.software];
|
||||||
|
// Checking pGroups.forks is the TypeScript safe way of checking hasForks
|
||||||
|
if (pGroups.forks && (instance.software === forkOf || software.forkOf === forkOf)) {
|
||||||
|
pGroups.forks.list.push(instance);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pGroups.others.push(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
function constructOptionFromInstance(instance: Instance): HTMLDivElement {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.setAttribute("x-option", instance.origin);
|
div.setAttribute("x-option", instance.origin);
|
||||||
const radio = document.createElement("input");
|
const radio = document.createElement("input");
|
||||||
|
@ -84,8 +141,35 @@ function createInstanceSelectOptions() {
|
||||||
label.appendChild(small);
|
label.appendChild(small);
|
||||||
div.appendChild(radio);
|
div.appendChild(radio);
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
instanceSelectForm.appendChild(div);
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createInstanceSelectOptions() {
|
||||||
|
// Erase all child nodes
|
||||||
|
preferredList.replaceChildren();
|
||||||
|
forksList.replaceChildren();
|
||||||
|
othersList.replaceChildren();
|
||||||
|
|
||||||
|
const { preferred, forks, others } = sortInstancesIntoPreferenceGroups();
|
||||||
|
|
||||||
|
preferredList.hidden = preferred.length === 0;
|
||||||
|
for (const instance of preferred) {
|
||||||
|
preferredList.appendChild(constructOptionFromInstance(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
forksDiv.hidden = forks === undefined;
|
||||||
|
if (forks) {
|
||||||
|
forkOfSpan.innerText = getName(knownSoftware, forks.of) ?? forks.of;
|
||||||
|
for (const instance of forks.list) {
|
||||||
|
forksList.appendChild(constructOptionFromInstance(instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
othersDiv.hidden = others.length === 0;
|
||||||
|
for (const instance of others) {
|
||||||
|
othersList.appendChild(constructOptionFromInstance(instance));
|
||||||
|
}
|
||||||
|
|
||||||
const firstInput = instanceSelectForm.querySelector("input");
|
const firstInput = instanceSelectForm.querySelector("input");
|
||||||
if (firstInput) firstInput.checked = true;
|
if (firstInput) firstInput.checked = true;
|
||||||
setRedirectButtonState(firstInput !== null);
|
setRedirectButtonState(firstInput !== null);
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
// I would've LOVED to use generics for this but unfortunately that's not possible.
|
// I would've LOVED to use generics for this but unfortunately that's not possible.
|
||||||
// Type safety, but at what cost... >~< thanks TypeScript
|
// Type safety, but at what cost... >~< thanks TypeScript
|
||||||
|
|
||||||
|
export function findDivOrFail(on: Element, selector: string): HTMLDivElement {
|
||||||
|
const element = on.querySelector(selector);
|
||||||
|
if (!(element instanceof HTMLDivElement))
|
||||||
|
throw new Error(`${selector} isn't a div`);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
export function findSpanOrFail(on: Element, selector: string): HTMLSpanElement {
|
export function findSpanOrFail(on: Element, selector: string): HTMLSpanElement {
|
||||||
const element = on.querySelector(selector);
|
const element = on.querySelector(selector);
|
||||||
if (!(element instanceof HTMLSpanElement))
|
if (!(element instanceof HTMLSpanElement))
|
||||||
|
|
|
@ -61,6 +61,10 @@ abbr[title] {
|
||||||
text-align: start;
|
text-align: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.inline-block {
|
.inline-block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
@ -157,6 +161,10 @@ abbr[title] {
|
||||||
margin-bottom: var(--large);
|
margin-bottom: var(--large);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.margin-none-bottom {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.square {
|
.square {
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue