Added distinction between basic and advanced mode

This commit is contained in:
Pax1601 2024-01-13 10:01:30 +01:00
parent 0f0ba4c725
commit d56a95cfa3
28 changed files with 1251 additions and 446 deletions

View File

@ -105,6 +105,10 @@ declare module "constants/constants" {
export const ROEs: string[];
export const reactionsToThreat: string[];
export const emissionsCountermeasures: string[];
export const ERAS: {
name: string;
chronologicalOrder: number;
}[];
export const ROEDescriptions: string[];
export const reactionsToThreatDescriptions: string[];
export const emissionsCountermeasuresDescriptions: string[];
@ -836,6 +840,7 @@ declare module "other/utils" {
}): UnitBlueprint | null;
export function getMarkerCategoryByName(name: string): "aircraft" | "helicopter" | "groundunit-sam" | "navyunit" | "groundunit-other";
export function getUnitDatabaseByCategory(category: string): import("unit/databases/aircraftdatabase").AircraftDatabase | import("unit/databases/helicopterdatabase").HelicopterDatabase | import("unit/databases/groundunitdatabase").GroundUnitDatabase | import("unit/databases/navyunitdatabase").NavyUnitDatabase | null;
export function getCategoryBlueprintIconSVG(category: string, unitName: string): string | false;
export function base64ToBytes(base64: string): ArrayBufferLike;
export function enumToState(state: number): string;
export function enumToROE(ROE: number): string;
@ -1600,6 +1605,7 @@ declare module "map/map" {
import { CoalitionAreaContextMenu } from "contextmenus/coalitionareacontextmenu";
import { AirbaseSpawnContextMenu } from "contextmenus/airbasespawnmenu";
export type MapMarkerVisibilityControl = {
"category"?: string;
"image": string;
"isProtected"?: boolean;
"name": string;
@ -1997,6 +2003,25 @@ declare module "unit/importexport/unitdatafileexport" {
showForm(units: Unit[]): void;
}
}
declare module "schemas/schema" {
import Ajv from "ajv";
import { AnySchemaObject } from "ajv/dist/core";
abstract class JSONSchemaValidator {
#private;
constructor(schema: AnySchemaObject);
getAjv(): Ajv;
getCompiledValidator(): any;
getErrors(): any;
getSchema(): AnySchemaObject;
validate(data: any): any;
}
export class AirbasesJSONSchemaValidator extends JSONSchemaValidator {
constructor();
}
export class ImportFileJSONSchemaValidator extends JSONSchemaValidator {
constructor();
}
}
declare module "unit/importexport/unitdatafileimport" {
import { Dialog } from "dialog/dialog";
import { UnitDataFile } from "unit/importexport/unitdatafile";

View File

@ -60,6 +60,11 @@
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
@ -646,7 +651,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {

97
manager/1.js Normal file
View File

@ -0,0 +1,97 @@
/* Get the list of DCS instances */
var instances = await DCSInstance.getInstances();
/* If there is only 1 DCS Instance and Olympus is not installed in it, go straight to the installation page (since there is nothing else to do) */
this.basic = instances.length === 1 && !instances[0].installed;
document.getElementById("loader").classList.add("hide");
/* Check if there are corrupted or outdate instances */
if (instances.some((instance) => {
return instance.installed && instance.error;
})) {
/* Ask the user for confirmation */
showErrorPopup("One or more Olympus instances are corrupted or need updating. Press Close to fix this.", async () => {
showWaitPopup("Please wait while your instances are being fixed.")
fixInstances(instances.filter((instance) => {
return instance.installed && instance.error;
})).then(
() => { location.reload() },
(err) => {
logger.error(err);
showErrorPopup(`An error occurred while trying to fix your installations. Please reinstall Olympus manually. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`);
}
)
})
}
/* Check which buttons should be enabled */
const installEnabled = true;
const manageEnabled = instances.some((instance) => { return instance.installed; });
/* Menu */
var menuPage = new MenuPage(this, {
installEnabled: installEnabled,
manageEnabled: manageEnabled
});
/* Installations */
this.installationsPage = new InstallationsPage(this, {
instances: instances
});
/* Instances */
this.instancesPage = new InstancesPage(this, {
instances: instances.filter((instance) => {
return instance.installed;
})
});
/* Connections */
this.connectionsPage = new ConnectionsPage(this);
/* Passwords */
this.passwordsPage = new PasswordsPage(this);
/* Result */
this.resultPage = new ResultPage(this, {
logLocation: path.join(__dirname, "..", "manager.log")
});
/* Create all the HTML pages */
document.body.appendChild(this.menuPage.getElement());
document.body.appendChild(this.installationsPage.getElement());
document.body.appendChild(this.instancesPage.getElement());
document.body.appendChild(this.connectionsPage.getElement());
document.body.appendChild(this.passwordsPage.getElement());
document.body.appendChild(this.resultPage.getElement());
/* In basic mode we directly show the connections page */
if (this.basic) {
const options = {
instance: instances[0],
basic: this.basic,
install: true
}
connectionsPage.options = {
...connectionsPage.options,
...options
}
passwordsPage.options = {
...passwordsPage.options,
...options
}
resultPage.options = {
...resultPage.options,
...options
}
/* Show the connections page directly */
instancesPage.hide();
connectionsPage.show();
} else {
/* Show the main menu */
menuPage.show();
}
}

View File

@ -1,4 +1,33 @@
<style>
#manager-connections .option {
background-color: var(--background);
border: 1px solid var(--offwhite);
width: 220px;
height: 60px;
color: var(--offwhite);
display: flex;
font-size: 18px;
font-weight: 600;
padding-left: 15px;
align-items: center;
border-radius: 5px;
cursor: pointer;
background-color: transparent;
color: var(--offwhite);
justify-content: center;
}
#manager-connections .option:hover {
color: var(--background);
background-color: var(--offwhite);
}
#manager-connections .buttons {
display: flex;
flex-direction: column;
row-gap: 15px;
}
#manager-connections .success,
#manager-connections .error {
position: absolute;
@ -29,65 +58,85 @@
</style>
<div id="manager-connections">
<div class="step-summary">
<div class="blue <%= !install || simplified? 'hide': '' %>">User path</div>
<div class="blue <%= singleInstance? 'hide': '' %>"><%= install? 'User path': 'Instance selection' %></div>
<div class="blue">Type of install</div>
<div class="white">Ports and address</div>
<div class="empty">Passwords</div>
<div class="empty"> <%= install? 'Install': 'Update' %></div>
</div>
<div class="content">
<div class="instructions">
<span>
Accept or modify port settings (optional)
</span>
<span>
If you are installing Olympus locally for Single player use, it's recommended you leave these as default and continue.
If you are installing a dedicated server, then follow the instructions available on the DCS Olympus Wiki.
</span>
</div>
<div class="input-group client-port">
<span>Client port
<img src="./icons/circle-info-solid.svg" title="This port is used to allow access to Olympus. Be sure to allow this port through your firewall if you want people to connect remotely">
</span>
<div>
<input type="number" min="1024" max="65535" value="<%= instance["clientPort"] %>">
<img class="success hide">
<div class="error hide">
<img> <span>Port already in use</span>
<% if (selectAutoOrManual) { %>
<div class="instructions">
<span>
Do you want to set port and address settings manually?
</span>
<span>
We can auto setup ports and addresses for you, or you can set the manually. <br>
If you don't have an understanding of how Olympus works, we recommend the auto option.
</span>
</div>
<div class="buttons">
<div class="option button auto">
Auto apply settings
</div>
<div class="option button manual">
Manually set options
</div>
</div>
</div>
<div class="input-group backend-port">
<span>Backend port
<img src="./icons/circle-info-solid.svg" title="This port is used to allow access to Olympus. Be sure to allow this port through your firewall if you want people to connect remotely.">
</span>
<div>
<input type="number" min="1024" max="65535" value="<%= instance["backendPort"] %>">
<img class="success hide">
<div class="error hide">
<img> <span>Port already in use</span>
<% } else { %>
<div class="instructions">
<span>
Enter the ports and address to use.
</span>
<span>
Select client and backend ports, making sure they are free to use with the provided check. <br>
Unless you want to support direct API calls to the backend, you can keep the address to localhost even for dedicated servers.
</span>
</div>
<div class="input-group client-port">
<span>Client port
<img src="./icons/circle-info-solid.svg" title="This port is used to allow access to Olympus. Be sure to allow this port through your firewall if you want people to connect remotely">
</span>
<div>
<input type="number" min="1024" max="65535" value="<%= activeInstance["clientPort"] %>">
<img class="success hide">
<div class="error hide">
<img> <span>Port already in use</span>
</div>
</div>
</div>
</div>
<div class="input-group backend-address">
<span>Backend address
<img src="./icons/circle-info-solid.svg" title="This is the backend address Olympus will listen on. Unless you know what you are doing, leave it as localhost, even for dedicated server installations.">
</span>
<input type="text" value="<%= instance["backendAddress"] %>">
</div>
<div class="input-group backend-port">
<span>Backend port
<img src="./icons/circle-info-solid.svg" title="This port is used to allow access to Olympus. Be sure to allow this port through your firewall if you want people to connect remotely.">
</span>
<div>
<input type="number" min="1024" max="65535" value="<%= activeInstance["backendPort"] %>">
<img class="success hide">
<div class="error hide">
<img> <span>Port already in use</span>
</div>
</div>
</div>
<div class="input-group backend-address">
<span>Backend address
<img src="./icons/circle-info-solid.svg" title="This is the backend address Olympus will listen on. Unless you know what you are doing, leave it as localhost, even for dedicated server installations.">
</span>
<input type="text" value="<%= activeInstance["backendAddress"] %>">
</div>
<% } %>
<div class="buttons-footer">
<% if (!simplified) { %>
<div class="button back">
Back
</div>
<% } %>
<div class="button next">
Next
</div>
</div>
<% if (!simplified) { %>
<div class="button cancel">
<%= install? "Cancel installation": "Cancel editing" %>
</div>
<% } %>
</div>
</div>

View File

@ -88,27 +88,41 @@
</style>
<div id="manager-installations">
<div class="step-summary">
<div class="white">User path</div>
<div class="white <%= singleInstance? 'hide': '' %>"><%= install? 'User path': 'Instance selection' %></div>
<div class="blue">Type of install</div>
<div class="empty">Ports and address</div>
<div class="empty">Passwords</div>
<div class="empty">Install</div>
<div class="empty"> <%= install? 'Install': 'Update' %></div>
</div>
<div class="content">
<div class="instructions">
<span>
Select a DCS path to install Olympus to.
<% if (install) { %>
Select a DCS path to install Olympus to.
<% } else { %>
Select an Olympus instance to edit.
<% } %>
</span>
<span>
We have automatically detected the following DCS installations under your Saved Games / DCS folder.
<% if (install) { %>
We have automatically detected the following DCS installations under your Saved Games / DCS folder.
<% } else { %>
These are the DCS instances in which Olympus has already been installed.
<% } %>
</span>
<span>
Please select which DCS installations you want to add Olympus to.
<% if (install) { %>
Please select which DCS installations you want to add Olympus to.
<% } else { %>
Please select which Olympus installations you want to edit.
<% } %>
</span>
</div>
<div class="scroll-container">
<div class="scrollable">
<% for (let i = 0; i < instances.length; i++) {%>
<div class="option <%= instances[i].installed? 'installed': '' %>" data-folder="<%= instances[i].folder %>">
<div class="option" data-folder="<%= instances[i].folder %>">
<span><%= instances[i].name %></span>
<span><img src="./icons/folder-open-solid.svg"> <%= instances[i].folder %></span>
<span class="<%= instances[i].installed? (instances[i].error? 'error': 'installed'): '' %>">
@ -118,9 +132,12 @@
<% } %>
</div>
</div>
<div class="button cancel">
Cancel installation
<% if (install) { %>
Cancel installation
<% } else { %>
Cancel editing
<% } %>
</div>
</div>
</div>

View File

@ -36,6 +36,18 @@
row-gap: 25px;
}
#manager-instances .option:not(.installed) {
background-color: var(--background-disabled);
}
#manager-instances .option:not(.installed) .info {
opacity: 50%;
}
#manager-instances .option:not(.installed) .server-data {
opacity: 50%;
}
#manager-instances>.instructions {
margin-bottom: 10px;
}
@ -192,6 +204,7 @@
}
#manager-instances .edit,
#manager-instances .install,
#manager-instances .uninstall,
#manager-instances .stop {
color: var(--offwhite);
@ -200,34 +213,36 @@
}
#manager-instances .edit:hover,
#manager-instances .install:hover,
#manager-instances .uninstall:hover,
#manager-instances .stop:hover {
color: var(--background);
background-color: var(--offwhite);
}
#manager-instances .install {
margin-left: auto;
}
</style>
<div id="manager-instances">
<div class="content">
<div class="button cancel">
<img src="./icons/chevron-left-solid.svg"/> Return to menu
</div>
<div class="instructions">
<span>
View and manage installs
</span>
<span>
The following Oympus installs have been identified. <br>You can start an Olympus server, modify settings and uninstall below.
The following DCS installations have been identified. <br>You can start an Olympus server, modify settings and uninstall below.
</span>
</div>
<div class="scroll-container">
<div class="scrollable">
<% for (let i = 0; i < instances.length; i++) {%>
<div class="option" data-folder="<%= instances[i].folder %>">
<div class="option <%= instances[i].installed? 'installed': '' %>" data-folder="<%= instances[i].folder %>">
<div class="instance-info">
<span><%= instances[i].name %></span>
<span class="<%= instances[i].installed? (instances[i].error? 'error': ''): '' %>">
<%= instances[i].installed? (instances[i].error? 'Corrupted/outdated Olympus installation': ''): '' %>
<span class="<%= instances[i].installed? (instances[i].error? 'error': 'installed'): '' %>">
<%= instances[i].installed? (instances[i].error? 'Corrupted/outdated Olympus installation': 'Olympus installed'): 'Olympus not installed' %>
</span>
<span><img src="./icons/folder-open-solid.svg"> <%= instances[i].folder %></span>
<div class="server-data">
@ -242,15 +257,15 @@
<div class="divider"></div>
<div class="info">
<div>Client port</div>
<div> <%= instances[i].clientPort %> </div>
<div> <%= instances[i].installed? instances[i].clientPort: "N/A" %> </div>
</div>
<div class="info">
<div>Backend port</div>
<div> <%= instances[i].backendPort %> </div>
<div> <%= instances[i].installed? instances[i].backendPort: "N/A" %> </div>
</div>
<div class="info">
<div>Backend address</div>
<div> <%= instances[i].backendAddress %> </div>
<div> <%= instances[i].installed? instances[i].backendAddress: "N/A" %> </div>
</div>
</div>
<div class="instance-buttons">
@ -263,6 +278,7 @@
</div>
<div class="button edit">Edit settings</div>
<div class="button install">Install Olympus</div>
<div class="button uninstall">Uninstall Olympus</div>
<div class="button open-browser hide">Open in browser</div>
<div class="button stop hide">Stop Olympus</div>

View File

@ -74,6 +74,11 @@
pointer-events: none;
}
#manager-menu .divider {
width: 460px;
border-color: var(--darkgray) !important;
}
</style>
<div id="manager-menu">
<div id="summary">
@ -83,10 +88,14 @@
</div>
<div id="menu">
<div class="option install <%= installEnabled? '': 'disabled' %>">
Install Olympus
Run Install wizard
</div>
<div class="option manage <%= manageEnabled? '': 'disabled' %>">
View / Manage installs
<div class="option edit <%= editEnabled? '': 'disabled' %>">
Update settings
</div>
<div class="divider"></div>
<div class="option uninstall <%= uninstallEnabled? '': 'disabled' %>">
Remove Olympus
</div>
</div>
</div>

View File

@ -3,7 +3,8 @@
</style>
<div id="manager-passwords">
<div class="step-summary">
<div class="blue <%= !install || simplified? 'hide': '' %>">User path</div>
<div class="blue <%= singleInstance? 'hide': '' %>"><%= install? 'User path': 'Instance selection' %></div>
<div class="blue">Type of install</div>
<div class="blue">Ports and address</div>
<div class="white">Passwords</div>
<div class="empty"> <%= install? 'Install': 'Update' %></div>
@ -41,7 +42,7 @@
Next
</div>
</div>
<% if (!simplified) { %>
<% if (!singleInstance) { %>
<div class="button cancel">
<%= install? "Cancel installation": "Cancel editing" %>
</div>

View File

@ -129,10 +129,10 @@
<img class="wait"><img class="success hide"><img class="error hide">
<div>
<span>
<%= instance.name %>
<%= activeInstance.name %>
</span>
<span><img src="./icons/folder-open-solid.svg">
<%= instance.folder %>
<%= activeInstance.folder %>
</span>
</div>
</div>

61
manager/ejs/type.ejs Normal file
View File

@ -0,0 +1,61 @@
<style>
#manager-type .option {
background-color: var(--background);
border: 1px solid var(--offwhite);
width: 220px;
height: 60px;
color: var(--offwhite);
display: flex;
font-size: 18px;
font-weight: 600;
padding-left: 15px;
align-items: center;
border-radius: 5px;
cursor: pointer;
background-color: transparent;
color: var(--offwhite);
justify-content: center;
}
#manager-type .option:hover {
color: var(--background);
background-color: var(--offwhite);
}
#manager-type .buttons {
display: flex;
flex-direction: column;
row-gap: 15px;
}
</style>
<div id="manager-type">
<div class="step-summary">
<div class="blue <%= singleInstance? 'hide': '' %>"><%= install? 'User path': 'Instance selection' %></div>
<div class="white">Type of install</div>
<div class="empty">Ports and address</div>
<div class="empty">Passwords</div>
<div class="empty"> <%= install? 'Install': 'Update' %></div>
</div>
<div class="content">
<div class="instructions">
<span>
Do you want to install Olympus for singleplayer or multiplayer?
</span>
<span>
Select Single player if you only want to play locally on your own computer. <br>
If you want Olympus to be used on a different computer or over the internet for a dedicated server, select the multiplayer option.
</span>
</div>
<div class="buttons">
<div class="option button singleplayer">
Singleplayer
</div>
<div class="option button multiplayer">
Multiplayer
</div>
</div>
<div class="button cancel">
<%= install? "Cancel installation": "Cancel editing" %>
</div>
</div>
</div>

67
manager/ejs/welcome.ejs Normal file
View File

@ -0,0 +1,67 @@
<style>
#manager-welcome {
display: flex;
flex-direction: column;
row-gap: 20px;
width: 100%;
justify-content: center;
align-items: center;
}
#manager-welcome span {
width: 40%;
text-align: center;
color: var(--offwhite);
}
#manager-welcome .option {
background-color: var(--background);
border: 1px solid var(--offwhite);
width: 460px;
height: 70px;
color: var(--offwhite);
display: flex;
font-size: 18px;
font-weight: 600;
padding-left: 15px;
align-items: center;
border-radius: 5px;
cursor: pointer;
background-color: transparent;
color: var(--offwhite);
}
#manager-welcome .option:hover {
color: var(--background);
background-color: var(--offwhite);
}
#manager-welcome .option.disabled {
pointer-events: none;
color: var(--darkgray);
border-color: var(--darkgray);
}
#manager-welcome .option * {
pointer-events: none;
}
</style>
<div id="manager-welcome">
<span style="font-size: 28px; font-weight: bold;">
Do you want to use the Olympus Manager in basic or advanced mode?
</span>
<span style="color: var(--gray);">
Basic mode is recommended for most users. <br>
Advanced mode is for those who know how Olympus works or for server owners.
</span>
<span style="color: var(--gray); font-weight: bold;">
You can change this setting at any time.
</span>
<div class="option basic">
Basic mode
</div>
<div class="option advanced">
Advanced mode
</div>
</div>

View File

@ -20,7 +20,7 @@
<button class="title-bar-button maximize"></button>
<button class="title-bar-button close"></button>
</div>
<div id="header">
<div id="header" class="hide">
<img class="main-icon" src="../img/OlympusLogoFinal_4k.png" \>
<div class="version">
<div> DCS Olympus Manager</div>
@ -28,6 +28,7 @@
</div>
<div class="link first" data-link="https://github.com/Pax1601/DCSOlympus/wiki/2.-User-Guide">User Guide</div>
<div class="link" data-link="https://github.com/Pax1601/DCSOlympus/wiki/Setup-Troubleshooting">Troubleshooting Guide</div>
<div id="switch-mode" class="link"> </div>
<div style="width: 15px;"></div>
<img class="link" data-link="https://github.com/Pax1601/DCSOlympus" src="./icons/github.svg"/>
<img class="link" data-link="https://discord.gg/pCfCykAdrw" src="./icons/discord.svg"/>

View File

@ -6,58 +6,73 @@ const { logger } = require("./filesystem")
*
*/
class ConnectionsPage extends ManagerPage {
onBackClicked;
onNextClicked;
onCancelClicked;
instance;
constructor(options) {
super(options);
constructor(manager, options) {
super(manager, options);
}
render(str) {
const element = this.getElement();
element.innerHTML = str;
if (this.element.querySelector(".back"))
this.element.querySelector(".back").addEventListener("click", (e) => this.onBackClicked(e));
if (this.element.querySelector(".button.auto"))
this.element.querySelector(".button.auto").addEventListener("click", (e) => this.onOptionSelected(true));
if (this.element.querySelector(".next"))
this.element.querySelector(".next").addEventListener("click", (e) => this.onNextClicked(e));
if (this.element.querySelector(".button.manual"))
this.element.querySelector(".button.manual").addEventListener("click", (e) => this.onOptionSelected(false));
if (this.element.querySelector(".cancel"))
this.element.querySelector(".cancel").addEventListener("click", (e) => this.onCancelClicked(e));
if (this.element.querySelector(".client-port"))
this.element.querySelector(".client-port").querySelector("input").addEventListener("change", async (e) => { this.setClientPort(Number(e.target.value)); })
this.element.querySelector(".client-port").querySelector("input").addEventListener("change", async (e) => { this.setClientPort(Number(e.target.value)); })
this.element.querySelector(".backend-port").querySelector("input").addEventListener("change", async (e) => { this.setBackendPort(Number(e.target.value)); })
this.element.querySelector(".backend-address").querySelector("input").addEventListener("change", async (e) => { this.instance.setBackendAddress(e.target.value); })
if (this.element.querySelector(".backend-port"))
this.element.querySelector(".backend-port").querySelector("input").addEventListener("change", async (e) => { this.setBackendPort(Number(e.target.value)); })
if (this.element.querySelector(".backend-address"))
this.element.querySelector(".backend-address").querySelector("input").addEventListener("change", async (e) => { this.manager.getActiveInstance().setBackendAddress(e.target.value); })
super.render();
}
show() {
this.instance = this.options.instance;
ejs.renderFile("./ejs/connections.ejs", this.options, {}, (err, str) => {
show(previousPage) {
ejs.renderFile("./ejs/connections.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
/* Call the port setters to check if the ports are free */
this.setClientPort(this.instance.clientPort);
this.setBackendPort(this.instance.backendPort);
this.setClientPort(this.manager.getActiveInstance().clientPort);
this.setBackendPort(this.manager.getActiveInstance().backendPort);
} else {
logger.error(err);
}
});
super.show();
super.show(previousPage);
}
onNextClicked() {
this.hide();
this.manager.passwordsPage.show(this);
}
onCancelClicked() {
this.hide();
this.manager.menuPage.show()
}
onOptionSelected(auto) {
this.options.selectAutoOrManual = false;
this.options.auto = auto;
if (auto) {
} else {
this.show();
}
}
/** Asynchronously check if the client port is free and if it is, set the new value
*
*/
async setClientPort(newPort) {
const success = await this.instance.setClientPort(newPort);
const success = await this.manager.getActiveInstance().setClientPort(newPort);
var successEls = this.element.querySelector(".client-port").querySelectorAll(".success");
for (let i = 0; i < successEls.length; i++) {
successEls[i].classList.toggle("hide", !success);
@ -72,7 +87,7 @@ class ConnectionsPage extends ManagerPage {
*
*/
async setBackendPort(newPort) {
const success = await this.instance.setBackendPort(newPort);
const success = await this.manager.getActiveInstance().setBackendPort(newPort);
var successEls = this.element.querySelector(".backend-port").querySelectorAll(".success");
for (let i = 0; i < successEls.length; i++) {
successEls[i].classList.toggle("hide", !success);

View File

@ -1,3 +1,4 @@
const { getManager } = require('./managerfactory')
var regedit = require('regedit')
const shellFoldersKey = 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders'
const saveGamesKey = '{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}'
@ -124,36 +125,7 @@ class DCSInstance {
/* Periodically "ping" Olympus to check if either the client or the backend are active */
window.setInterval(async () => {
await this.getData();
var page = document.getElementById("manager-instances");
if (page) {
var instanceDivs = page.querySelectorAll(`.option`);
for (let i = 0; i < instanceDivs.length; i++) {
if (instanceDivs[i].dataset.folder == this.folder) {
var instanceDiv = instanceDivs[i];
if (instanceDiv.querySelector(".webserver.online") !== null) {
instanceDiv.querySelector(".webserver.online").classList.toggle("hide", !this.webserverOnline)
instanceDiv.querySelector(".webserver.offline").classList.toggle("hide", this.webserverOnline)
instanceDiv.querySelector(".backend.online").classList.toggle("hide", !this.backendOnline)
instanceDiv.querySelector(".backend.offline").classList.toggle("hide", this.backendOnline)
if (this.backendOnline) {
instanceDiv.querySelector(".fps .data").innerText = this.fps;
instanceDiv.querySelector(".load .data").innerText = this.load;
}
instanceDiv.querySelector(".button.start").classList.toggle("hide", this.webserverOnline)
instanceDiv.querySelector(".button.uninstall").classList.toggle("hide", this.webserverOnline)
instanceDiv.querySelector(".button.edit").classList.toggle("hide", this.webserverOnline)
instanceDiv.querySelector(".button.open-browser").classList.toggle("hide", !this.webserverOnline)
instanceDiv.querySelector(".button.stop").classList.toggle("hide", !this.webserverOnline)
if (this.webserverOnline)
instanceDiv.querySelector(".button.start").classList.remove("loading")
}
}
}
}
getManager().instancesPage.update();
}, 1000);
}
@ -370,7 +342,7 @@ class DCSInstance {
/* Uninstall this instance */
uninstall() {
showConfirmPopup("Are you sure you want to completely remove this Olympus installation?", () =>
showConfirmPopup("<div style='font-size: 18px; max-width: 100%'> Are you sure you want to remove Olympus? </div> If you click Accept, the Olympus mod will be removed from your DCS installation.", () =>
uninstallInstance(this.folder, this.name).then(
() => {
location.reload();

View File

@ -1,14 +1,12 @@
const DCSInstance = require("./dcsinstance");
const ManagerPage = require("./managerpage");
const ejs = require('ejs')
const { logger } = require("./filesystem")
const { logger } = require("./filesystem");
const { showConfirmPopup } = require("./popup");
class InstallationsPage extends ManagerPage {
onCancelClicked;
setSelectedInstance;
constructor(options) {
super(options);
constructor(manager, options) {
super(manager, options);
}
render(str) {
@ -19,17 +17,18 @@ class InstallationsPage extends ManagerPage {
options[i].onclick = (e) => {this.onOptionClicked(e);}
}
this.element.querySelector(".cancel").addEventListener("click", (e) => this.onCancelClicked(e));
if (this.element.querySelector(".cancel"))
this.element.querySelector(".cancel").addEventListener("click", (e) => this.onCancelClicked(e));
super.render();
}
async onOptionClicked(e) {
this.setSelectedInstance((await DCSInstance.getInstances()).find((instance) => {return instance.folder === e.target.dataset.folder}));
this.onInstanceSelection((await DCSInstance.getInstances()).find((instance) => {return instance.folder === e.target.dataset.folder}));
}
show() {
ejs.renderFile("./ejs/installations.ejs", this.options, {}, (err, str) => {
show(previousPage) {
ejs.renderFile("./ejs/installations.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
} else {
@ -37,7 +36,31 @@ class InstallationsPage extends ManagerPage {
}
});
super.show();
super.show(previousPage);
}
onInstanceSelection(activeInstance) {
this.manager.options.activeInstance = activeInstance;
this.manager.options.install = !activeInstance.installed;
/* Show the connections page */
if (!activeInstance.installed || !this.managers.options.install) {
this.hide();
this.manager.typePage.show(this);
} else {
showConfirmPopup("<div style='font-size: 18px; max-width: 100%'> Olympus is already installed in this instance! </div> If you click Accept, it will be installed again and all changes, e.g. custom databases or mods support, will be lost. Are you sure you want to continue?",
() => {
this.hide();
this.manager.typePage.show(this);
}
)
}
}
onCancelClicked(e) {
/* Go back to the main menu */
this.hide();
this.manager.menuPage.show();
}
}

View File

@ -6,12 +6,10 @@ const { exec } = require("child_process");
const { logger } = require("./filesystem")
class InstancesPage extends ManagerPage {
onCancelClicked;
setSelectedInstance;
startInstance;
constructor(options) {
super(options);
constructor(manager, options) {
super(manager, options);
}
render(str) {
@ -22,6 +20,11 @@ class InstancesPage extends ManagerPage {
editButtons[i].onclick = (e) => {this.onEditClicked(e);}
}
var installButtons = this.element.querySelectorAll(".button.install");
for (let i = 0; i < installButtons.length; i++) {
installButtons[i].onclick = (e) => {this.onInstallClicked(e);}
}
var uninstallButtons = this.element.querySelectorAll(".button.uninstall");
for (let i = 0; i < uninstallButtons.length; i++) {
uninstallButtons[i].onclick = (e) => {this.onUninstallClicked(e);}
@ -47,19 +50,9 @@ class InstancesPage extends ManagerPage {
stopButtons[i].onclick = (e) => {this.onStopClicked(e);}
}
this.element.querySelector(".cancel").addEventListener("click", (e) => this.onCancelClicked(e));
super.render();
}
async onEditClicked(e) {
this.getClickedInstance(e).then((instance) => {
instance.webserverOnline || instance.backendOnline? showErrorPopup("Error, the selected Olympus instance is currently active, please stop Olympus before editing it!") :
this.setSelectedInstance(instance);
}
);
}
async onStartServerClicked(e) {
e.target.closest(".collapse").classList.add("loading");
this.getClickedInstance(e).then((instance) => instance.startServer());
@ -78,6 +71,30 @@ class InstancesPage extends ManagerPage {
this.getClickedInstance(e).then((instance) => instance.stop());
}
async onEditClicked(e) {
this.getClickedInstance(e).then((instance) => {
if (instance.webserverOnline || instance.backendOnline) {
showErrorPopup("Error, the selected Olympus instance is currently active, please stop Olympus before editing it!")
} else {
this.manager.options.activeInstance = instance;
this.manager.options.install = false;
this.manager.options.singleInstance = false;
this.hide();
this.manager.typePage.show(this);
}
});
}
async onInstallClicked(e) {
this.getClickedInstance(e).then((instance) => {
this.manager.options.activeInstance = instance;
this.manager.options.install = true;
this.manager.options.singleInstance = false;
this.hide();
this.manager.typePage.show(this);
});
}
async onUninstallClicked(e) {
this.getClickedInstance(e).then((instance) => {
instance.webserverOnline || instance.backendOnline? showErrorPopup("Error, the selected Olympus instance is currently active, please stop Olympus before uninstalling it!") : instance.uninstall();
@ -92,8 +109,8 @@ class InstancesPage extends ManagerPage {
});
}
show() {
ejs.renderFile("./ejs/instances.ejs", this.options, {}, (err, str) => {
show(previousPage) {
ejs.renderFile("./ejs/instances.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
} else {
@ -101,7 +118,51 @@ class InstancesPage extends ManagerPage {
}
});
super.show();
var instanceDivs = this.element.querySelectorAll(`.option`);
for (let i = 0; i < instanceDivs.length; i++) {
var instanceDiv = instanceDivs[i];
var instance = this.manager.options.instances.find((instance) => { return instance.folder === instanceDivs[i].dataset.folder;})
if (instance) {
instanceDiv.querySelector(".button.install").classList.toggle("hide", instance.installed);
instanceDiv.querySelector(".button.start").classList.toggle("hide", !instance.installed)
instanceDiv.querySelector(".button.uninstall").classList.toggle("hide", !instance.installed)
instanceDiv.querySelector(".button.edit").classList.toggle("hide", !instance.installed)
}
}
super.show(previousPage);
}
update() {
var instanceDivs = this.element.querySelectorAll(`.option`);
for (let i = 0; i < instanceDivs.length; i++) {
var instance = this.manager.options.instances.find((instance) => { return instance.folder === instanceDivs[i].dataset.folder;})
if (instance && instance.installed) {
var instanceDiv = instanceDivs[i];
if (instanceDiv.querySelector(".webserver.online") !== null) {
instanceDiv.querySelector(".webserver.online").classList.toggle("hide", !instance.webserverOnline)
instanceDiv.querySelector(".webserver.offline").classList.toggle("hide", instance.webserverOnline)
instanceDiv.querySelector(".backend.online").classList.toggle("hide", !instance.backendOnline)
instanceDiv.querySelector(".backend.offline").classList.toggle("hide", instance.backendOnline)
if (this.backendOnline) {
instanceDiv.querySelector(".fps .data").innerText = instance.fps;
instanceDiv.querySelector(".load .data").innerText = instance.load;
}
instanceDiv.querySelector(".button.start").classList.toggle("hide", instance.webserverOnline)
instanceDiv.querySelector(".button.uninstall").classList.toggle("hide", instance.webserverOnline)
instanceDiv.querySelector(".button.edit").classList.toggle("hide", instance.webserverOnline)
instanceDiv.querySelector(".button.open-browser").classList.toggle("hide", !instance.webserverOnline)
instanceDiv.querySelector(".button.stop").classList.toggle("hide", !instance.webserverOnline)
if (this.webserverOnline)
instanceDiv.querySelector(".button.start").classList.remove("loading")
}
}
}
}
}

View File

@ -6,258 +6,131 @@ const ResultPage = require('./result');
const InstancesPage = require('./instances');
const DCSInstance = require('./dcsinstance');
const { showErrorPopup, showWaitPopup } = require('./popup');
const { showErrorPopup, showWaitPopup, showConfirmPopup } = require('./popup');
const { fixInstances } = require('./filesystem');
const { logger } = require("./filesystem")
const path = require("path")
const fs = require("fs");
const WelcomePage = require("./welcome");
const TypePage = require("./type");
class Manager {
simplified = true;
options = {
logLocation: path.join(__dirname, "..", "manager.log"),
configLoaded: false
};
welcomePage = null;
installationsPage = null;
typePage = null;
connectionsPage = null;
passwordsPage = null;
resultPage = null;
instancesPage = null;
constructor() {
}
async start() {
/* Get the list of DCS instances */
var instances = await DCSInstance.getInstances();
/* If there is only 1 DCS Instance and Olympus is not installed in it, go straight to the installation page (since there is nothing else to do) */
this.simplified = instances.length === 1 && !instances[0].installed;
document.getElementById("loader").classList.add("hide");
/* Check if there are corrupted or outdate instances */
if (instances.some((instance) => {
return instance.installed && instance.error;
})) {
/* Ask the user for confirmation */
showErrorPopup("One or more Olympus instances are corrupted or need updating. Press Close to fix this.", async () => {
showWaitPopup("Please wait while your instances are being fixed.")
fixInstances(instances.filter((instance) => {
return instance.installed && instance.error;
})).then(
() => { location.reload() },
(err) => {
logger.error(err);
showErrorPopup(`An error occurred while trying to fix your installations. Please reinstall Olympus manually. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`);
}
)
})
}
/* Check which buttons should be enabled */
const installEnabled = true;
const manageEnabled = instances.some((instance) => { return instance.installed; });
/* Menu */
var menuPage = new MenuPage();
menuPage.options = {
...menuPage.options,
installEnabled: installEnabled,
manageEnabled: manageEnabled
}
/* When the install button is clicked go the installation page */
menuPage.onInstallClicked = (e) => {
menuPage.hide();
installationsPage.show();
}
/* When the manage button is clicked go to the instances page in "manage mode" (i.e. manage = true) */
menuPage.onManageClicked = (e) => {
menuPage.hide();
instancesPage.show();
}
/* Installations */
var installationsPage = new InstallationsPage();
installationsPage.options = {
...installationsPage.options,
instances: instances
}
installationsPage.setSelectedInstance = (activeInstance) => {
/* Set the active options for the pages */
const options = {
instance: activeInstance,
simplified: this.simplified,
install: true
if (fs.existsSync("options.json")) {
/* Load the options from the json file */
try {
this.options = {...this.options, ...JSON.parse(fs.readFileSync("options.json"))};
this.options.configLoaded = true;
} catch (e) {
logger.error(`An error occurred while reading the options.json file: ${e}`);
}
connectionsPage.options = {
...connectionsPage.options,
...options
}
if (!this.options.configLoaded) {
/* Hide the loading page */
document.getElementById("loader").classList.add("hide");
/* Show page to select basic vs advanced mode */
this.welcomePage = new WelcomePage(this);
document.body.appendChild(this.welcomePage.getElement());
this.welcomePage.show();
}
else {
document.getElementById("header").classList.remove("hide");
if (this.options.mode === "basic") {
document.getElementById("switch-mode").innerText = "Advanced mode";
document.getElementById("switch-mode").onclick = () => { this.switchMode("advanced"); }
}
passwordsPage.options = {
...passwordsPage.options,
...options
}
resultPage.options = {
...resultPage.options,
...options
else {
document.getElementById("switch-mode").innerText = "Basic mode";
document.getElementById("switch-mode").onclick = () => { this.switchMode("basic"); }
}
/* Show the connections page */
installationsPage.hide();
connectionsPage.show();
/* Get the list of DCS instances */
this.options.instances = await DCSInstance.getInstances();
connectionsPage.onBackClicked = (e) => {
/* Show the installation page */
connectionsPage.hide();
installationsPage.show();
}
}
installationsPage.onCancelClicked = (e) => {
/* Go back to the main menu */
installationsPage.hide();
menuPage.show();
}
/* Instances */
var instancesPage = new InstancesPage();
instancesPage.options = {
...instancesPage.options,
instances: instances.filter((instance) => { return instance.installed; })
}
instancesPage.setSelectedInstance = (activeInstance) => {
/* Set the active options for the pages */
const options = {
instance: activeInstance,
simplified: this.simplified,
install: false
}
connectionsPage.options = {
...connectionsPage.options,
...options
}
passwordsPage.options = {
...passwordsPage.options,
...options
}
resultPage.options = {
...resultPage.options,
...options
/* Check if there are corrupted or outdate instances */
if (this.options.instances.some((instance) => {
return instance.installed && instance.error;
})) {
/* Ask the user for confirmation */
showConfirmPopup("<div style='font-size: 18px; max-width: 100%;'>One or more of your Olympus instances are not up to date! </div> <br> <br> If you have just updated Olympus this is normal. <br> <br> Press Accept and the Manager will fix your instances for you. <br> Press Close to update your instances manually using the Installation Wizard", async () => {
showWaitPopup("Please wait while your instances are being fixed.")
fixInstances(this.options.instances.filter((instance) => {
return instance.installed && instance.error;
})).then(
() => { location.reload() },
(err) => {
logger.error(err);
showErrorPopup(`An error occurred while trying to fix your installations. Please reinstall Olympus manually. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`);
}
)
})
}
/* Show the connections page */
instancesPage.hide();
connectionsPage.show();
this.options.installEnabled = true;
this.options.editEnabled = this.options.instances.find(instance => instance.installed);
this.options.uninstallEnabled = this.options.instances.find(instance => instance.installed);
connectionsPage.onBackClicked = (e) => {
/* Show the instances page */
connectionsPage.hide();
instancesPage.show();
}
}
instancesPage.onCancelClicked = (e) => {
/* Go back to the main menu */
instancesPage.hide();
menuPage.show();
}
/* Hide the loading page */
document.getElementById("loader").classList.add("hide");
/* Connections */
var connectionsPage = new ConnectionsPage();
connectionsPage.onNextClicked = async (e) => {
let activeInstance = connectionsPage.options.instance;
if (activeInstance) {
/* Check that the selected ports are free before proceeding */
if (await activeInstance.checkClientPort(activeInstance.clientPort) && await activeInstance.checkBackendPort(activeInstance.backendPort)) {
connectionsPage.hide();
passwordsPage.show();
} else {
showErrorPopup("Please make sure the selected ports are not already in use.")
}
this.options.singleInstance = this.options.instances.length === 1;
/* Create all the HTML pages */
this.menuPage = new MenuPage(this);
this.installationsPage = new InstallationsPage(this);
this.typePage = new TypePage(this);
this.connectionsPage = new ConnectionsPage(this);
this.passwordsPage = new PasswordsPage(this);
this.resultPage = new ResultPage(this);
this.instancesPage = new InstancesPage(this);
document.body.appendChild(this.menuPage.getElement());
document.body.appendChild(this.installationsPage.getElement());
document.body.appendChild(this.typePage.getElement());
document.body.appendChild(this.connectionsPage.getElement());
document.body.appendChild(this.passwordsPage.getElement());
document.body.appendChild(this.resultPage.getElement());
document.body.appendChild(this.instancesPage.getElement());
if (this.options.mode === "basic") {
/* In basic mode no dashboard is shown */
this.menuPage.show();
} else {
showErrorPopup(`An error has occurred, please restart the Olympus Manager. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`)
/* In advanced mode we go directly to the dashboard */
this.instancesPage.show();
}
}
connectionsPage.onCancelClicked = (e) => {
/* Go back to the main menu */
connectionsPage.hide();
menuPage.show();
}
}
/* Passwords */
var passwordsPage = new PasswordsPage();
passwordsPage.onBackClicked = (e) => {
/* Go back to the connections page */
let activeInstance = connectionsPage.options.instance;
if (activeInstance) {
passwordsPage.hide();
connectionsPage.show();
} else {
showErrorPopup(`An error has occurred, please restart the Olympus Manager. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`)
}
}
passwordsPage.onNextClicked = (e) => {
let activeInstance = connectionsPage.options.instance;
if (activeInstance) {
/* Check that all the passwords have been set */
if (activeInstance.gameMasterPassword === "" || activeInstance.blueCommanderPassword === "" || activeInstance.redCommanderPassword === "") {
showErrorPopup("Please fill all the password inputs.")
}
else if (activeInstance.gameMasterPassword === activeInstance.blueCommanderPassword || activeInstance.blueCommanderPassword === activeInstance.redCommanderPassword || activeInstance.gameMasterPassword === activeInstance.redCommanderPassword) {
showErrorPopup("All the passwords must be different from each other.")
} else {
passwordsPage.hide();
resultPage.show();
resultPage.startInstallation();
}
} else {
showErrorPopup(`An error has occurred, please restart the Olympus Manager. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`)
}
getActiveInstance() {
return this.options.activeInstance;
}
}
passwordsPage.onCancelClicked = (e) => {
/* Go back to the main menu */
passwordsPage.hide();
menuPage.show();
}
/* Result */
var resultPage = new ResultPage({logLocation: path.join(__dirname, "..", "manager.log")});
resultPage.onBackClicked = (e) => {
/* Reload the page to apply changes */
resultPage.hide();
location.reload();
}
resultPage.onCancelClicked = (e) => {
/* Reload the page to apply changes */
resultPage.hide();
location.reload();
}
/* Create all the HTML pages */
document.body.appendChild(menuPage.getElement());
document.body.appendChild(installationsPage.getElement());
document.body.appendChild(instancesPage.getElement());
document.body.appendChild(connectionsPage.getElement());
document.body.appendChild(passwordsPage.getElement());
document.body.appendChild(resultPage.getElement());
/* In simplified mode we directly show the connections page */
if (this.simplified) {
const options = {
instance: instances[0],
simplified: this.simplified,
install: true
}
connectionsPage.options = {
...connectionsPage.options,
...options
}
passwordsPage.options = {
...passwordsPage.options,
...options
}
resultPage.options = {
...resultPage.options,
...options
}
/* Show the connections page directly */
instancesPage.hide();
connectionsPage.show();
} else {
/* Show the main menu */
menuPage.show();
}
switchMode(newMode) {
var options = JSON.parse(fs.readFileSync("options.json"));
options.mode = newMode;
fs.writeFileSync("options.json", JSON.stringify(options));
location.reload();
}
}

View File

@ -0,0 +1,15 @@
var manager = null;
function getManager() {
if (manager) {
return manager;
} else {
const Manager = require("./manager");
manager = new Manager();
return manager;
}
}
module.exports = {
getManager: getManager
};

View File

@ -1,8 +1,11 @@
class ManagerPage {
manager;
element;
options;
previousPage;
constructor(options) {
constructor(manager, options) {
this.manager = manager;
this.options = options ?? {};
this.element = document.createElement('div');
this.element.classList.add("manager-page", "hide");
@ -12,8 +15,11 @@ class ManagerPage {
return this.element;
}
show() {
show(previousPage) {
this.element.classList.remove("hide");
if (previousPage !== undefined)
this.previousPage = previousPage;
}
hide() {
@ -28,6 +34,21 @@ class ManagerPage {
buttons[i].classList.toggle("open");
})
}
/* Connect the back, next and cancel buttons */
if (this.element.querySelector(".back"))
this.element.querySelector(".back").addEventListener("click", (e) => this.onBackClicked(e));
if (this.element.querySelector(".next"))
this.element.querySelector(".next").addEventListener("click", (e) => this.onNextClicked(e));
if (this.element.querySelector(".cancel"))
this.element.querySelector(".cancel").addEventListener("click", (e) => this.onCancelClicked(e));
}
onBackClicked() {
this.hide();
this.previousPage.show()
}
}

View File

@ -1,14 +1,11 @@
const ManagerPage = require("./managerpage");
const ejs = require('ejs')
const { logger } = require("./filesystem")
const { logger } = require("./filesystem");
const { showConfirmPopup } = require("./popup");
class MenuPage extends ManagerPage {
onInstallClicked;
onUpdateClicked;
onManageClicked;
constructor(options) {
super(options);
constructor(manager, options) {
super(manager, options);
}
render(str) {
@ -16,15 +13,14 @@ class MenuPage extends ManagerPage {
element.innerHTML = str;
element.querySelector(".install").addEventListener("click", (e) => this.onInstallClicked(e));
element.querySelector(".manage").addEventListener("click", (e) => this.onManageClicked(e));
element.querySelector(".edit").addEventListener("click", (e) => this.onEditClicked(e));
element.querySelector(".uninstall").addEventListener("click", (e) => this.onUninstallClicked(e));
super.render();
}
show() {
this.instance = this.options.instance;
ejs.renderFile("./ejs/menu.ejs", this.options, {}, (err, str) => {
show(previousPage) {
ejs.renderFile("./ejs/menu.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
} else {
@ -32,8 +28,60 @@ class MenuPage extends ManagerPage {
}
});
super.show();
super.show(previousPage);
}
/* When the install button is clicked go the installation page */
onInstallClicked(e) {
this.manager.options.install = true;
if (this.manager.options.singleInstance) {
this.manager.options.activeInstance = this.manager.options.instances[0];
/* Show the connections page */
if (!this.manager.options.activeInstance.installed) {
this.hide();
this.manager.typePage.show(this);
} else {
showConfirmPopup("<div style='font-size: 18px; max-width: 100%'> Olympus is already installed in this instance! </div> If you click Accept, it will be installed again and all changes, e.g. custom databases or mods support, will be lost. Are you sure you want to continue?",
() => {
this.hide();
this.manager.typePage.show(this);
}
)
}
} else {
this.hide();
this.manager.installationsPage.show(this);
}
}
/* When the edit button is clicked go to the instances page */
onEditClicked(e) {
this.hide();
this.manager.options.install = false;
if (this.manager.options.singleInstance) {
this.manager.options.activeInstance = this.manager.options.instances[0];
this.manager.typePage.show(this);
} else {
this.manager.installationsPage.show(this);
}
}
/* When the remove button is clicked go to the instances page */
onUninstallClicked(e) {
this.manager.options.install = false;
if (this.manager.options.singleInstance) {
this.manager.options.activeInstance = this.manager.options.instances[0];
this.manager.options.activeInstance.uninstall();
} else {
// TODO select instance to remove
}
}
}
module.exports = MenuPage;

View File

@ -3,38 +3,23 @@ const ejs = require('ejs')
const { logger } = require("./filesystem")
class PasswordsPage extends ManagerPage {
onBackClicked;
onNextClicked;
onCancelClicked;
constructor(options) {
super(options);
constructor(manager, options) {
super(manager, options);
}
render(str) {
const element = this.getElement();
element.innerHTML = str;
if (this.element.querySelector(".back"))
this.element.querySelector(".back").addEventListener("click", (e) => this.onBackClicked(e));
if (this.element.querySelector(".next"))
this.element.querySelector(".next").addEventListener("click", (e) => this.onNextClicked(e));
if (this.element.querySelector(".cancel"))
this.element.querySelector(".cancel").addEventListener("click", (e) => this.onCancelClicked(e));
this.element.querySelector(".game-master").querySelector("input").addEventListener("change", async (e) => { this.instance.setGameMasterPassword(e.target.value); })
this.element.querySelector(".blue-commander").querySelector("input").addEventListener("change", async (e) => { this.instance.setBlueCommanderPassword(e.target.value); })
this.element.querySelector(".red-commander").querySelector("input").addEventListener("change", async (e) => { this.instance.setRedCommanderPassword(e.target.value); })
this.element.querySelector(".game-master").querySelector("input").addEventListener("change", async (e) => { this.manager.getActiveInstance().setGameMasterPassword(e.target.value); })
this.element.querySelector(".blue-commander").querySelector("input").addEventListener("change", async (e) => { this.manager.getActiveInstance().setBlueCommanderPassword(e.target.value); })
this.element.querySelector(".red-commander").querySelector("input").addEventListener("change", async (e) => { this.manager.getActiveInstance().setRedCommanderPassword(e.target.value); })
super.render();
}
show() {
this.instance = this.options.instance;
ejs.renderFile("./ejs/passwords.ejs", this.options, {}, (err, str) => {
show(previousPage) {
ejs.renderFile("./ejs/passwords.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
} else {
@ -42,7 +27,18 @@ class PasswordsPage extends ManagerPage {
}
});
super.show();
super.show(previousPage);
}
onNextClicked() {
this.hide();
this.manager.resultPage.show();
this.manager.resultPage.startInstallation();
}
onCancelClicked() {
this.hide();
this.manager.menuPage.show()
}
}

View File

@ -1,5 +1,24 @@
// TODO: we can probably refactor this to be a bit cleaner
function showInfoPopup(message, onCloseCallback) {
document.getElementById("grayout").classList.remove("hide");
document.getElementById("popup").classList.remove("hide");
document.getElementById("popup").querySelector(".error").classList.add("hide");
document.getElementById("popup").querySelector(".wait").classList.add("hide");
document.getElementById("popup").querySelector(".confirm").classList.remove("hide");
document.getElementById("popup").querySelector(".close-popup").classList.remove("hide");
document.getElementById("popup").querySelector(".accept-popup").classList.add("hide");
/* Not using event listeners to make sure we only have one callback */
document.getElementById("popup").querySelector(".close-popup").onclick = (e) => {
hidePopup();
if (onCloseCallback)
onCloseCallback();
}
document.getElementById("popup").querySelector(".content").innerHTML = message;
}
function showErrorPopup(message, onCloseCallback) {
document.getElementById("grayout").classList.remove("hide");
document.getElementById("popup").classList.remove("hide");
@ -61,6 +80,7 @@ function hidePopup() {
}
module.exports = {
showInfoPopup: showInfoPopup,
showErrorPopup: showErrorPopup,
showConfirmPopup: showConfirmPopup,
showWaitPopup: showWaitPopup,

View File

@ -1,5 +1,3 @@
const Manager = require('./manager');
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
const { exec, spawn } = require("child_process");
@ -10,7 +8,8 @@ const https = require('follow-redirects').https;
const fs = require('fs');
const AdmZip = require("adm-zip");
const { Octokit } = require('octokit');
const { logger } = require("./filesystem")
const { logger } = require("./filesystem");
const { getManager } = require('./managerFactory');
const VERSION = "{{OLYMPUS_VERSION_NUMBER}}";
logger.log(`Running in ${__dirname}`);
@ -257,15 +256,13 @@ contextBridge.exposeInMainWorld(
}
});
/* New instance of the manager app */
const manager = new Manager();
/* On content loaded */
window.addEventListener('DOMContentLoaded', async () => {
/* Compute the height of the content page */
computePagesHeight();
document.getElementById("loader").classList.remove("hide");
await manager.start();
await getManager().start();
/* Compute the height of the content page to account for the pages created by the manager*/
computePagesHeight();
@ -273,7 +270,8 @@ window.addEventListener('DOMContentLoaded', async () => {
var links = document.querySelectorAll(".link");
for (let i = 0; i < links.length; i++) {
links[i].addEventListener("click", (e) => {
exec("start " + e.target.dataset.link);
if (e.target.dataset.link)
exec("start " + e.target.dataset.link);
})
}
})
@ -298,4 +296,5 @@ function computePagesHeight() {
ipcRenderer.on("check-version", () => {
/* Check if a new version is available */
checkVersion();
})
})

View File

@ -4,27 +4,19 @@ const ejs = require('ejs')
const { logger } = require("./filesystem")
class ResultPage extends ManagerPage {
onBackClicked;
onNextClicked;
onCancelClicked;
constructor(options) {
super(options);
constructor(manager, options) {
super(manager, options);
}
render(str) {
const element = this.getElement();
element.innerHTML = str;
this.element.querySelector(".back").addEventListener("click", (e) => this.onBackClicked(e));
super.render();
}
show() {
this.instance = this.options.instance;
ejs.renderFile("./ejs/result.ejs", this.options, {}, (err, str) => {
show(previousPage) {
ejs.renderFile("./ejs/result.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
} else {
@ -32,14 +24,18 @@ class ResultPage extends ManagerPage {
}
});
super.show();
super.show(previousPage);
}
onBackClicked() {
location.reload();
}
/** Installation is performed by using an then chain of async functions. Installation is aborted on any error along the chain
*
*/
startInstallation() {
installHooks(this.instance.folder).then(
installHooks(this.manager.getActiveInstance().folder).then(
() => {
this.applyStepSuccess(".hook");
},
@ -47,7 +43,7 @@ class ResultPage extends ManagerPage {
this.applyStepFailure(".hook");
return Promise.reject(err);
}
).then(() => installMod(this.instance.folder, this.instance.name)).then(
).then(() => installMod(this.manager.getActiveInstance().folder, this.manager.getActiveInstance().name)).then(
() => {
this.applyStepSuccess(".mod");
},
@ -55,7 +51,7 @@ class ResultPage extends ManagerPage {
this.applyStepFailure(".mod");
return Promise.reject(err);
}
).then(() => installJSON(this.instance.folder)).then(
).then(() => installJSON(this.manager.getActiveInstance().folder)).then(
() => {
this.applyStepSuccess(".json");
},
@ -63,7 +59,7 @@ class ResultPage extends ManagerPage {
this.applyStepFailure(".json");
return Promise.reject(err);
}
).then(() => applyConfiguration(this.instance.folder, this.instance)).then(
).then(() => applyConfiguration(this.manager.getActiveInstance().folder, this.manager.getActiveInstance())).then(
() => {
this.applyStepSuccess(".config");
},
@ -71,7 +67,7 @@ class ResultPage extends ManagerPage {
this.applyStepFailure(".config");
return Promise.reject(err);
}
).then(() => installShortCuts(this.instance.folder, this.instance.name)).then(
).then(() => installShortCuts(this.manager.getActiveInstance().folder, this.manager.getActiveInstance().name)).then(
() => {
this.applyStepSuccess(".shortcuts");
},

View File

@ -0,0 +1,49 @@
const ManagerPage = require("./managerpage");
const ejs = require('ejs')
const { logger } = require("./filesystem")
/** Type of install page, allows the user to select single player or multi player installation
*
*/
class TypePage extends ManagerPage {
constructor(manager, options) {
super(manager, options);
}
render(str) {
const element = this.getElement();
element.innerHTML = str;
this.element.querySelector(".singleplayer").addEventListener("click", (e) => this.onOptionSelected(false));
this.element.querySelector(".multiplayer").addEventListener("click", (e) => this.onOptionSelected(true));
super.render();
}
show(previousPage) {
ejs.renderFile("./ejs/type.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
} else {
logger.error(err);
}
});
super.show(previousPage);
}
onCancelClicked() {
this.hide();
this.manager.menuPage.show()
}
onOptionSelected(multiplayer) {
this.manager.options.multiplayer = multiplayer;
this.hide();
this.manager.connectionsPage.options.selectAutoOrManual = true;
this.manager.connectionsPage.show(this);
}
}
module.exports = TypePage;

View File

@ -0,0 +1,52 @@
const ManagerPage = require("./managerpage");
const ejs = require('ejs')
const { logger } = require("./filesystem")
const fs = require("fs");
const { showErrorPopup } = require("./popup");
class WelcomePage extends ManagerPage {
constructor(manager, options) {
super(manager, options);
}
render(str) {
const element = this.getElement();
element.innerHTML = str;
element.querySelector(".basic").addEventListener("click", (e) => this.onbasicClicked(e));
element.querySelector(".advanced").addEventListener("click", (e) => this.onAdvancedClicked(e));
super.render();
}
show(previousPage) {
ejs.renderFile("./ejs/welcome.ejs", {...this.options, ...this.manager.options}, {}, (err, str) => {
if (!err) {
this.render(str);
} else {
logger.error(err);
}
});
super.show(previousPage);
}
onbasicClicked(e) {
this.createOptionsFile("basic");
}
onAdvancedClicked(e) {
this.createOptionsFile("advanced");
}
createOptionsFile(mode) {
try {
fs.writeFileSync("options.json", JSON.stringify({mode: mode}));
location.reload();
} catch (e) {
showErrorPopup(`A critical error occurred, check ${this.manager.options.logLocation} for more info.`)
}
}
}
module.exports = WelcomePage;

317
manager/manager.log Normal file
View File

@ -0,0 +1,317 @@
======================= New log starting at Thu Jan 11 2024 16:07:31 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Development build detected, skipping version checks...
======================= New log starting at Thu Jan 11 2024 16:11:52 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:11:54 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:11:56 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:13:03 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:13:31 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:13:41 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:13:48 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:23:11 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:32
30| <div id="manager-connections">
31| <div class="step-summary">
>> 32| <div class="blue <%= !install || basic? 'hide': '' %>">User path</div>
33| <div class="white">Ports and address</div>
34| <div class="empty">Passwords</div>
35| <div class="empty"> <%= install? 'Install': 'Update' %></div>
basic is not defined
at eval ("./ejs/connections.ejs":12:38)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:70:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:24:03 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:32
30| <div id="manager-connections">
31| <div class="step-summary">
>> 32| <div class="blue <%= !install || basic? 'hide': '' %>">User path</div>
33| <div class="white">Ports and address</div>
34| <div class="empty">Passwords</div>
35| <div class="empty"> <%= install? 'Install': 'Update' %></div>
basic is not defined
at eval ("./ejs/connections.ejs":12:38)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:70:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:24:25 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:32
30| <div id="manager-connections">
31| <div class="step-summary">
>> 32| <div class="blue <%= !install || basic? 'hide': '' %>">User path</div>
33| <div class="white">Ports and address</div>
34| <div class="empty">Passwords</div>
35| <div class="empty"> <%= install? 'Install': 'Update' %></div>
basic is not defined
at eval ("./ejs/connections.ejs":12:38)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:71:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:24:45 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:32
30| <div id="manager-connections">
31| <div class="step-summary">
>> 32| <div class="blue <%= !install || basic? 'hide': '' %>">User path</div>
33| <div class="white">Ports and address</div>
34| <div class="empty">Passwords</div>
35| <div class="empty"> <%= install? 'Install': 'Update' %></div>
basic is not defined
at eval ("./ejs/connections.ejs":12:38)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:71:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:25:20 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:32
30| <div id="manager-connections">
31| <div class="step-summary">
>> 32| <div class="blue <%= !install || basic? 'hide': '' %>">User path</div>
33| <div class="white">Ports and address</div>
34| <div class="empty">Passwords</div>
35| <div class="empty"> <%= install? 'Install': 'Update' %></div>
basic is not defined
at eval ("./ejs/connections.ejs":12:38)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:78:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:28:55 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:52
50| </span>
51| <div>
>> 52| <input type="number" min="1024" max="65535" value="<%= instance["clientPort"] %>">
53| <img class="success hide">
54| <div class="error hide">
55| <img> <span>Port already in use</span>
instance is not defined
at eval ("./ejs/connections.ejs":18:26)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:78:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:29:02 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:52
50| </span>
51| <div>
>> 52| <input type="number" min="1024" max="65535" value="<%= instance["clientPort"] %>">
53| <img class="success hide">
54| <div class="error hide">
55| <img> <span>Port already in use</span>
instance is not defined
at eval ("./ejs/connections.ejs":18:26)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:78:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:31:06 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:52
50| </span>
51| <div>
>> 52| <input type="number" min="1024" max="65535" value="<%= instance["clientPort"] %>">
53| <img class="success hide">
54| <div class="error hide">
55| <img> <span>Port already in use</span>
instance is not defined
at eval ("./ejs/connections.ejs":18:26)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:41:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:77:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:37:31 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
ReferenceError: ./ejs/connections.ejs:52
50| </span>
51| <div>
>> 52| <input type="number" min="1024" max="65535" value="<%= instance["clientPort"] %>">
53| <img class="success hide">
54| <div class="error hide">
55| <img> <span>Port already in use</span>
instance is not defined
at eval ("./ejs/connections.ejs":18:26)
at connections (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ConnectionsPage.show (D:\Documents\DCSOlympus\manager\javascripts\connections.js:38:13)
at Manager.start (D:\Documents\DCSOlympus\manager\javascripts\manager.js:77:42)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async D:\Documents\DCSOlympus\manager\javascripts\preload.js:268:5 {
path: './ejs/connections.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:38:57 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:39:52 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:41:14 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:41:25 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:41:48 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:42:27 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:42:52 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:43:06 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:43:24 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
======================= New log starting at Thu Jan 11 2024 16:54:16 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
======================= New log starting at Thu Jan 11 2024 16:54:21 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
ReferenceError: ./ejs/passwords.ejs:6
4| <div id="manager-passwords">
5| <div class="step-summary">
>> 6| <div class="blue <%= !install || singleInstance? 'hide': '' %>">User path</div>
7| <div class="blue">Ports and address</div>
8| <div class="white">Passwords</div>
9| <div class="empty"> <%= install? 'Install': 'Update' %></div>
install is not defined
at eval ("./ejs/passwords.ejs":12:27)
at passwords (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at PasswordsPage.show (D:\Documents\DCSOlympus\manager\javascripts\passwords.js:35:13)
at ConnectionsPage.onNextClicked (D:\Documents\DCSOlympus\manager\javascripts\connections.js:58:36)
at HTMLDivElement.<anonymous> (D:\Documents\DCSOlympus\manager\javascripts\connections.js:21:87) {
path: './ejs/passwords.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:54:49 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
ReferenceError: ./ejs/passwords.ejs:44
42| </div>
43| </div>
>> 44| <% if (!basic) { %>
45| <div class="button cancel">
46| <%= install? "Cancel installation": "Cancel editing" %>
47| </div>
basic is not defined
at eval ("./ejs/passwords.ejs":18:8)
at passwords (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at PasswordsPage.show (D:\Documents\DCSOlympus\manager\javascripts\passwords.js:35:13)
at ConnectionsPage.onNextClicked (D:\Documents\DCSOlympus\manager\javascripts\connections.js:58:36)
at HTMLDivElement.<anonymous> (D:\Documents\DCSOlympus\manager\javascripts\connections.js:21:87) {
path: './ejs/passwords.ejs'
}
======================= New log starting at Thu Jan 11 2024 16:55:57 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
======================= New log starting at Fri Jan 12 2024 08:51:22 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Development build detected, skipping version checks...
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
======================= New log starting at Fri Jan 12 2024 08:53:17 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
======================= New log starting at Fri Jan 12 2024 08:53:42 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
ReferenceError: ./ejs/result.ejs:132
130| <div>
131| <span>
>> 132| <%= instance.name %>
133| </span>
134| <span><img src="./icons/folder-open-solid.svg">
135| <%= instance.folder %>
instance is not defined
at eval ("./ejs/result.ejs":27:26)
at result (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:274:36)
at exports.renderFile (D:\Documents\DCSOlympus\manager\node_modules\ejs\lib\ejs.js:491:10)
at ResultPage.show (D:\Documents\DCSOlympus\manager\javascripts\result.js:25:13)
at PasswordsPage.onNextClicked (D:\Documents\DCSOlympus\manager\javascripts\passwords.js:40:33)
at HTMLDivElement.<anonymous> (D:\Documents\DCSOlympus\manager\javascripts\managerpage.js:39:87) {
path: './ejs/result.ejs'
}
======================= New log starting at Fri Jan 12 2024 08:54:41 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
======================= New log starting at Fri Jan 12 2024 08:56:11 GMT+0100 (Central European Standard Time) =======================
Running in D:\Documents\DCSOlympus\manager\javascripts
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3000
Instance C:\Users\dpassoni\Saved Games\dcs.openbeta client port set to 3001
Installing hooks in C:\Users\dpassoni\Saved Games\dcs.openbeta
Error installing hooks in C:\Users\dpassoni\Saved Games\dcs.openbeta: Error: ENOENT: no such file or directory, lstat 'D:\Documents\DCSOlympus\scripts\OlympusHook.lua'

View File

@ -273,13 +273,13 @@ input {
left: 0px;
width: 100%;
height: 100%;
background-color: black;
opacity: 30%;
background-color: white;
opacity: 15%;
z-index: 999;
}
#popup {
width: 400px;
width: 450px;
height: fit-content;
min-height: 200px;
position: absolute;
@ -290,7 +290,7 @@ input {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px;
padding: 20px 40px;
align-items: start;
z-index: 999;
}