Remove old web interface

This commit is contained in:
Hornwitser committed 2020-09-22 22:06:03 +02:00
1 parent bca949f7be
commit fbf2843f5b
56 files changed
+1 -1424

No files matched your search

-2
View File
@@ -27,13 +27,11 @@
"@clusterio/slave": "file:./packages/slave",
"eslint": "^7.2.0",
"fs-extra": "^8.1.0",
"html5-validator": "^1.2.1",
"jsdoc": "^3.6.3",
"jsonwebtoken": "^8.2.1",
"jszip": "^3.2.2",
"lerna": "^3.22.1",
"mocha": "^6.2.0",
"mocha.parallel": "^0.15.5",
"nyc": "^14.1.1",
"phin": "^3.4.1"
}
-37
View File
@@ -23,8 +23,6 @@ const path = require("path");
const fs = require("fs-extra");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const moment = require("moment");
const request = require("request");
const setBlocking = require("set-blocking");
const events = require("events");
const yargs = require("yargs");
@@ -72,23 +70,6 @@ app.use(bodyParser.urlencoded({
app.use(fileUpload());
app.use(compression());
// dynamic HTML generations with EJS
app.set("view engine", "ejs");
app.set("views", ["views", "plugins"]);
// give ejs access to some interesting information
app.use(function(req, res, next){
let externalAddress = masterConfig.get("master.external_address");
res.locals.root = externalAddress ? new URL(externalAddress).pathname : "/";
res.locals.res = res;
res.locals.req = req;
res.locals.masterPlugins = masterPlugins;
res.locals.slaves = db.slaves;
res.locals.moment = moment;
next();
});
require("./src/routes")(app);
// Set folder to serve static content from (the website)
app.use(express.static(path.join(__dirname, "static")));
app.use(express.static("static")); // Used for data export files
@@ -438,24 +419,6 @@ async function shutdown() {
}
}
// wrap a request in an promise
async function downloadPage(url) {
return new Promise((resolve, reject) => {
request(url, (error, response, body) => {
resolve(body);
});
});
}
app.get("/api/modmeta", async function(req, res) {
endpointHitCounter.labels(req.route.path).inc();
res.header("Access-Control-Allow-Origin", "*");
res.setHeader("Content-Type", "application/json");
let modData = await downloadPage("https://mods.factorio.com/api/mods/" + req.query.modname);
res.send(modData);
});
/**
* Base class for master server connections
*
-106
View File
@@ -1,106 +0,0 @@
"use strict";
var http = require("http");
var https = require("https");
var fs = require("fs-extra");
function makeDirectory(path){
return new Promise((resolve, reject) => {
fs.mkdirp(path, function(err){
if(err){
console.error("Unable to mkdirp "+path);
console.error(err);
resolve(false);
} else {
console.log("mkdirp "+path);
resolve(true);
}
});
});
}
function download(url, file, callback){
return new Promise((resolve, reject) => {
let pathArray = file.split("/");
pathArray.pop(); // remove filename from the end
if(pathArray.length >= 1){
// this might be an invalid path!
fs.stat(pathArray.join("/"), (err, stat) => {
if(err){
makeDirectory(pathArray.join("/")).then(() => {
doDownload(url, file, callback);
});
} else {
doDownload(url, file, callback);
}
});
} else {
doDownload(url, file, callback);
}
function doDownload(url, file, callback){
var writeStream = fs.createWriteStream(file);
let protocol = http;
if(url.split(":")[0] == "https") protocol = https;
var request = protocol.get(url, function(response) {
response.pipe(writeStream);
response.on("end", () => {
if(callback && typeof callback == "function") callback(file);
console.log("Downloaded "+file+" from "+url);
resolve();
});
});
}
});
}
var directories = [
"sharedMods",
"instances",
];
let downloadList = [
{
url: "https://code.jquery.com/jquery.js",
file: "static/external/jquery.js",
},
{
url: "https://code.jquery.com/ui/1.12.1/jquery-ui.js",
file: "static/external/jquery-ui.js",
},
{
url: "https://momentjs.com/downloads/moment.min.js",
file: "static/external/moment.min.js",
},
{
url: "https://craig.global.ssl.fastly.net/js/mousetrap/mousetrap.min.js",
file: "static/external/mousetrap.min.js",
},
{
url: "https://fonts.googleapis.com/css?family=Roboto",
file: "static/external/css/Roboto.css",
},
];
// initiate folder creations and downloads
function processMkdirRecursive(callback){
let item = directories.shift();
makeDirectory(item).then(() => {
if(directories.length == 0){
if(callback) callback();
} else {
processMkdirRecursive(callback);
}
});
}
function processDownloadRecursive(callback){
let item = downloadList.shift();
download(item.url, item.file, item.callback).then(() => {
if(downloadList.length == 0){
if(callback) callback();
} else {
processDownloadRecursive(callback);
}
});
}
if (module === require.main) {
processMkdirRecursive(processDownloadRecursive);
}
+1 -5
View File
@@ -6,8 +6,7 @@
"version": "2.0.0-alpha0",
"main": "master.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"install": "node npm_post_install"
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"clusteriomaster": "./master.js"
@@ -23,16 +22,13 @@
"body-parser": "^1.18.2",
"compression": "^1.7.2",
"cookie-parser": "^1.4.3",
"ejs": "^2.5.7",
"express": "^4.16.2",
"express-fileupload": "1.2.0",
"fs-extra": "^8.1.0",
"jsonwebtoken": "^8.2.1",
"jszip": "^3.2.2",
"moment": "^2.22.2",
"node-factorio-api": "^0.3.8",
"node-forge": "^0.10.0",
"request": "^2.83.0",
"set-blocking": "^2.0.0",
"ws": "^7.2.3",
"yargs": "^14.2.0"
-15
View File
@@ -1,15 +0,0 @@
"use strict";
module.exports = function(app) {
app.get("/", function(req, res) {
res.render("index");
});
app.get("/nodes", function(req, res) {
res.render("nodes");
});
app.get("/settings", function(req, res) {
res.render("settings");
});
app.get("/nodeDetails", function(req, res) {
res.render("nodeDetails");
});
};
-12
View File
@@ -1,12 +0,0 @@
/*!
* Bootswatch v4.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2018 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v4.1.3 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#ee5f5b;--orange:#fd7e14;--yellow:#f89406;--green:#62c462;--teal:#20c997;--cyan:#5bc0de;--white:#fff;--gray:#7A8288;--gray-dark:#3A3F44;--primary:#3A3F44;--secondary:#7A8288;--success:#62c462;--info:#5bc0de;--warning:#f89406;--danger:#ee5f5b;--light:#e9ecef;--dark:#272B30;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-family-monospace:SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}*,*::before,*::after{-webkit-box-sizing:border-box;box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-size:0.9375rem;font-weight:400;line-height:1.5;color:#aaa;text-align:left;background-color:#272B30}[tabindex="-1"]:focus{outline:0 !important}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:0.5rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-original-title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#fff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#d9d9d9;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):hover,a:not([href]):not([tabindex]):focus{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}pre,code,kbd,samp{font-family:SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:0.75rem;padding-bottom:0.75rem;color:#7A8288;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:0.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{padding:0;border-style:none}input[type="radio"],input[type="checkbox"]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{outline-offset:-2px;-webkit-appearance:none}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none !important}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{margin-bottom:0.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}h1,.h1{font-size:2.34375rem}h2,.h2{font-size:1.875rem}h3,.h3{font-size:1.640625rem}h4,.h4{font-size:1.40625rem}h5,.h5{font-size:1.171875rem}h6,.h6{font-size:0.9375rem}.lead{font-size:1.171875rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-heigLine truncated
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/ms-icon-70x70.png"/>
<square150x150logo src="/ms-icon-150x150.png"/>
<square310x310logo src="/ms-icon-310x310.png"/>
<TileColor>#ffffff</TileColor>
</tile>
</msapplication>
</browserconfig>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,41 +0,0 @@
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

-185
View File
@@ -1,185 +0,0 @@
/*! terminal.js v2.0 | (c) 2014 Erik Österberg | https://github.com/eosterberg/terminaljs */
var Terminal = (function () {
// PROMPT_TYPE
var PROMPT_INPUT = 1, PROMPT_PASSWORD = 2, PROMPT_CONFIRM = 3
var fireCursorInterval = function (inputField, terminalObj) {
var cursor = terminalObj._cursor
setTimeout(function () {
if (inputField.parentElement && terminalObj._shouldBlinkCursor) {
cursor.style.visibility = cursor.style.visibility === 'visible' ? 'hidden' : 'visible'
fireCursorInterval(inputField, terminalObj)
} else {
cursor.style.visibility = 'visible'
}
}, 500)
}
var firstPrompt = true;
promptInput = function (terminalObj, message, PROMPT_TYPE, callback) {
var shouldDisplayInput = (PROMPT_TYPE === PROMPT_INPUT)
var inputField = document.createElement('input')
inputField.style.position = 'absolute'
inputField.style.zIndex = '-100'
inputField.style.outline = 'none'
inputField.style.border = 'none'
inputField.style.opacity = '0'
inputField.style.fontSize = '0.2em'
terminalObj._inputLine.textContent = ''
terminalObj._input.style.display = 'block'
terminalObj.html.appendChild(inputField)
fireCursorInterval(inputField, terminalObj)
if (message.length) terminalObj.print(PROMPT_TYPE === PROMPT_CONFIRM ? message + ' (y/n)' : message)
inputField.onblur = function () {
terminalObj._cursor.style.display = 'none'
}
inputField.onfocus = function () {
inputField.value = terminalObj._inputLine.textContent
terminalObj._cursor.style.display = 'inline'
}
terminalObj.html.onclick = function () {
inputField.focus()
}
inputField.onkeydown = function (e) {
if (e.which === 37 || e.which === 39 || e.which === 38 || e.which === 40 || e.which === 9) {
e.preventDefault()
} else if (shouldDisplayInput && e.which !== 13) {
setTimeout(function () {
terminalObj._inputLine.textContent = inputField.value
}, 1)
}
}
inputField.onkeyup = function (e) {
if (PROMPT_TYPE === PROMPT_CONFIRM || e.which === 13) {
terminalObj._input.style.display = 'none'
var inputValue = inputField.value
if (shouldDisplayInput) terminalObj.print(inputValue)
terminalObj.html.removeChild(inputField)
if (typeof(callback) === 'function') {
if (PROMPT_TYPE === PROMPT_CONFIRM) {
callback(inputValue.toUpperCase()[0] === 'Y' ? true : false)
} else callback(inputValue)
}
}
}
if (firstPrompt) {
firstPrompt = false
setTimeout(function () { inputField.focus() }, 50)
} else {
inputField.focus()
}
}
var terminalBeep
var TerminalConstructor = function (id) {
if (!terminalBeep) {
terminalBeep = document.createElement('audio')
var source = '<source src="http://www.erikosterberg.com/terminaljs/beep.'
terminalBeep.innerHTML = source + 'mp3" type="audio/mpeg">' + source + 'ogg" type="audio/ogg">'
terminalBeep.volume = 0.05
}
this.html = document.createElement('div')
this.html.className = 'Terminal'
if (typeof(id) === 'string') { this.html.id = id }
this._innerWindow = document.createElement('div')
this._output = document.createElement('p')
this._inputLine = document.createElement('span') //the span element where the users input is put
this._cursor = document.createElement('span')
this._input = document.createElement('p') //the full element administering the user input, including cursor
this._shouldBlinkCursor = true
this.beep = function () {
terminalBeep.load()
terminalBeep.play()
}
this.print = function (message) {
var newLine = document.createElement('div')
newLine.textContent = message
this._output.appendChild(newLine)
}
this.input = function (message, callback) {
promptInput(this, message, PROMPT_INPUT, callback)
}
this.password = function (message, callback) {
promptInput(this, message, PROMPT_PASSWORD, callback)
}
this.confirm = function (message, callback) {
promptInput(this, message, PROMPT_CONFIRM, callback)
}
this.clear = function () {
this._output.innerHTML = ''
}
this.sleep = function (milliseconds, callback) {
setTimeout(callback, milliseconds)
}
this.setTextSize = function (size) {
this._output.style.fontSize = size
this._input.style.fontSize = size
}
this.setTextColor = function (col) {
this.html.style.color = col
this._cursor.style.background = col
}
this.setBackgroundColor = function (col) {
this.html.style.background = col
}
this.setWidth = function (width) {
this.html.style.width = width
}
this.setHeight = function (height) {
this.html.style.height = height
}
this.blinkingCursor = function (bool) {
bool = bool.toString().toUpperCase()
this._shouldBlinkCursor = (bool === 'TRUE' || bool === '1' || bool === 'YES')
}
this._input.appendChild(this._inputLine)
this._input.appendChild(this._cursor)
this._innerWindow.appendChild(this._output)
this._innerWindow.appendChild(this._input)
this.html.appendChild(this._innerWindow)
this.setBackgroundColor('black')
this.setTextColor('white')
this.setTextSize('1em')
this.setWidth('100%')
this.setHeight('100%')
this.html.style.fontFamily = 'Monaco, Courier'
this.html.style.margin = '0'
this._innerWindow.style.padding = '10px'
this._input.style.margin = '0'
this._output.style.margin = '0'
this._cursor.style.background = 'white'
this._cursor.innerHTML = 'C' //put something in the cursor..
this._cursor.style.display = 'none' //then hide it
this._input.style.display = 'none'
}
return TerminalConstructor
}())
-9
View File
@@ -1,9 +0,0 @@
export function getParameterByName(name, url) {
if(!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if(!results) return null;
if(!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
-218
View File
@@ -1,218 +0,0 @@
(function (){
ensureSetting("Periodically update storage screen", "boolean", true);
}())
function ensureSetting(setting, type, defaultSetting) {
let settings
try {
settings = JSON.parse(localStorage.settings);
} catch (e) {
}
if(!settings) settings = {};
if(typeof settings[setting] != type) {
settings[setting] = defaultSetting;
console.log("Fixed setting: " + setting + " | " + defaultSetting)
}
localStorage.settings = JSON.stringify(settings)
}
// debug tools
debugTools = {
addItem: function(name, count){
console.log(`Attempting to add ${count} ${name}`)
postJSON("api/place", {
instanceName: "unknown",
instanceID: "unknown",
unique: "unknown",
name: name,
count: count,
}, function(data){
console.log(data);
});
},
removeItem: function(name, count){
console.log(`Attempting to remove ${count} ${name}`)
postJSON("api/remove", {
instanceName: "unknown",
instanceID: "unknown",
unique: "unknown",
name: name,
count: count,
}, function(data){
console.log(data);
});
}
}
let cachedInstanceNames = {};
async function getInstanceName(instanceID){
let instance = cachedInstanceNames[instanceID];
if(!instance){
let slaves = await getJSON("/api/slaves");
try {
for(id in slaves){
cachedInstanceNames[id] = slaves[id].instanceName;
}
} catch(e){
console.log("Error while looking for instance name!");
console.log(e);
}
return cachedInstanceNames[instanceID] || instanceID;
} else {
return cachedInstanceNames[instanceID];
}
}
var g = {}
contents = {
"iron-plate":100,
"copper-plate":7312,
}
// nice functions
// hash a string to a hash
function djb2(str){
var hash = 5381;
for (var i = 0; i < str.length; i++) {
hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */
}
return hash;
}
// get queryString parameters
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
// callback(err, json)
function getJSON(url, callback) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
if(callback) callback(null, xhr.response);
resolve(xhr.response);
} else {
if(callback) callback(status);
reject(status);
}
};
// triggers if connection is refused
xhr.onerror = function(e){
if(callback) callback(e);
reject(e);
};
xhr.send();
});
};
// callback(err, json)
function postJSON(url, data, callback) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
if(callback) callback(null, xhr.response);
resolve(xhr.response);
} else {
if(callback) callback(status);
reject(status);
}
};
// triggers if connection is refused
xhr.onerror = function(e){
if(callback) callback(e);
reject(e);
};
xhr.send(JSON.stringify(data));
});
};
// return Boolean
function isJSON(string){
let stringIsJson = false;
let x
try {
x = JSON.parse(string);
} catch (e){
return false;
}
if(typeof x == "object" || typeof string == "object"){
stringIsJson = true;
}
return stringIsJson;
}
// hash a string to a color
function hashColor(str) {
var hash = djb2(str);
var r = (hash & 0xFF0000) >> 16;
var g = (hash & 0x00FF00) >> 8;
var b = hash & 0x0000FF;
return "#" + ("0" + r.toString(16)).substr(-2) + ("0" + g.toString(16)).substr(-2) + ("0" + b.toString(16)).substr(-2);
}
// exactly what you would expect it to, returns String
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// hide the HTML object passed as argument #1
function hideThis(object) {
object.style.visibility = "hidden";
}
Date.prototype.yyyymmdd = function(time) { // http://stackoverflow.com/questions/3066586/get-string-in-yyyymmdd-format-from-js-date-object
var mm = this.getMonth() + 1; // getMonth() is zero-based
var dd = this.getDate();
if(mm<10)mm = "0"+mm
if(dd<10)dd = "0"+dd
console.log(this.getFullYear())
return this.getFullYear()+""+mm+""+dd+ ""; // padding
};
var date = new Date();
function replaceAll(target, search, replacement) {
return target.split(search).join(replacement);
};
function getItemIconClass(name) {
if (factorioItemMetadata.has(name)) {
return `item-${name}`;
} else {
return "item-unknown-item";
}
}
window.factorioLocale = new Map();
$.getJSON(`${root}export/locale.json`, (locale) => {
window.factorioLocale = new Map(locale);
});
window.factorioItemMetadata = new Map();
$.getJSON(`${root}export/item-metadata.json`, (itemMetadata) => {
window.factorioItemMetadata = new Map(itemMetadata);
console.log(factorioItemMetadata.get("electronic-circuit"));
let style = document.createElement("style");
style.type = "text/css";
document.head.appendChild(style);
for (let [name, meta] of itemMetadata) {
style.sheet.insertRule([
`.item-${name} {`,
` background-image: url("${root}export/item-spritesheet.png");`,
" background-repeat: no-repeat;",
` background-position: -${meta.x}px -${meta.y}px;`,
` height: ${meta.size}px;`,
` width: ${meta.size}px;`,
"}\n",
].join(""));
}
});
-41
View File
@@ -1,41 +0,0 @@
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}
-3
View File
@@ -1,3 +0,0 @@
#node-stats .breadcrumb-item {
height: auto;
}
-255
View File
@@ -1,255 +0,0 @@
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
/// code below here
// declaring globals
var chartsByID = {};
// update the online indicator dot
setInterval(function(){
getJSON("/api/slaves", function(err, slaveData){
let indicator = document.querySelector("#online-indicator");
$(indicator).removeClass('fa-signal');
$(indicator).removeClass('fa-dizzy');
$(indicator).removeClass('fa-plug');
if(err){
// our request threw an error, most likely master is unavailable so we show yellow indicator
indicator.style.color = "yellow";
$(indicator).addClass('fa-plug');
indicator.title = "Master server unavailable";
// compare with Math.floor(x/100000) allows us to check if they are within 10s of each other
} else if(Math.floor(slaveData[getParameterByName("instanceID")].time/100000) === Math.floor(Date.now()/100000)){
indicator.style.color = "green";
$(indicator).addClass('fa-signal');
indicator.title = "Slave is online";
} else {
indicator.style.color = "red";
$(indicator).addClass('fa-dizzy');
indicator.title = "Slave is offline";
}
});
}, 1000);
function regexModDetails(modFileName) {
let m;
let results = [];
const regex = /(.+)_(\d+\.\d+\.\d+)\.zip/gm;
while ((m = regex.exec(modFileName)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, _) => {
results.push(match);
});
}
return results
}
populateSlaveInfo();
function populateSlaveInfo(){
let instanceID = getParameterByName("instanceID");
if(!instanceID){
throw "We need instanceID! Also, *funny joke* but it doesn't work after I standardized on calling it instanceID";
}
getJSON("/api/slaves", function(err, slaveData){
/*
{"-1530507550":{
"time":"1495475926375",
"rconPort":"8714",
"rconPassword":"hidden",
"serverPort":"14345",
"unique":"-1530507550",
"publicIP":"localhost",
"mods":[
{
"modName":"clusterio_1.0.0.zip",
"hash":"341feb6c60918c83f7f3a6a14a4a308aef18dda6"
},{
"modName":"clusterio_1.0.1.zip",
"hash":"aee7a4b67ece19bddf236312fe408a5d4b67248d"
},{
"modName":"clusterio_1.1.0.zip",
"hash":"18e2f7e402d716e3dd1c1458b7fab2d0bb29eccf"
}],
"playerCount":"0",
"instanceName":"t",
"mac":"44-85-00-D2-7E-D6"}
}
*/
let slave = slaveData[instanceID];
let HTML = '<div class="jumbotron mt-5"><div id="header">' +
'<h1 class="display-4"><i id="online-indicator" class="mr-3 fas"></i> ' + slave.instanceName+"</h1>";
HTML += '<div class="stats" id="node-stats">' +
'<nav class="mt-3" aria-label="breadcrumb">\n' +
' <ol class="breadcrumb align-content-center"><li class="breadcrumb-item">Host: '+slave.mac+'</li>' +
'<li class="breadcrumb-item">Unique: '+slave.unique+'</li>';
if(slave.publicIP !== "localhost"){
HTML += '<li class="breadcrumb-item">IP: '+slave.publicIP+':'+slave.serverPort+'</li>';
} else {
HTML += '<li class="breadcrumb-item">This server is not configured for incoming connections</li>';
}
if(slave.meta)
for(let key in slave.meta){
let t = slave.meta[key];
if(typeof t == "string"){
HTML += "<li class=\"breadcrumb-item\">"+key+": "+t+"</li>";
}
}
HTML += '<li class="breadcrumb-item">Last seen: <span id="lastSeenDate">'+moment(Number(slave.time)).fromNow()+"</span></li>";
HTML += '<li class="breadcrumb-item">Online players: '+slave.playerCount+"</li></ol></nav>";
HTML += "</div>"; // end of displayBody
// list mods and other metadata
HTML += '<h2 class="subtitle d-inline">Mods</h2><a id="fetch-mod-data" class="btn btn-primary float-right m-2">Fetch Mod Data</a>' +
'<table id="modlist" class="table table-striped table-hover">' +
' <thead>\n' +
' <tr>\n' +
' <th scope="col">#</th>\n' +
' <th scope="col">Version</th>\n' +
' <th scope="col">Name</th>\n' +
' <th scope="col">Summary</th>\n' +
' </tr>\n' +
' </thead>' +
' <tbody>';
for(let i = 0; i < slave.mods[0].modName.length; i++){
let modRegexResults = regexModDetails(slave.mods[0].modName[i]);
HTML += `<tr>
<th scope="row">${i + 1}</th>
<td>${modRegexResults[2]}</td>
<td>${modRegexResults[1]}</td>
<td></td>
</tr>`
}
HTML += "</ul>";
HTML += "</div>"; // end of left container
// terminal
// HTML += '<div id="terminal"></div>';
document.querySelector("#body > #details").innerHTML = HTML;
// makeTerminal();
$('#fetch-mod-data').on("click", downloadSaveModData);
});
}
function downloadSaveModData() {
let modRows = $("#modlist tbody tr");
for (let i = 0; i < modRows.length; i++) {
let modName = modRows[i].children[2].innerText;
$.getJSON( "/api/modmeta?modname=" + modName, function( data ) {
modRows[i].children[2].innerHTML = data.title;
modRows[i].children[3].innerHTML = data.summary
});
}
}
var slaveLogin = {};
function makeTerminal(){
myTerminal = new Terminal();
document.querySelector("#terminal").appendChild(myTerminal.html);
// use jQuery to allow the user to drag the window around
$("#terminal").draggable({
handle:".titleBar",
});
myTerminal.print('Welcome to Clusterio rcon!');
myTerminal.input('', handleTerminalInput);
if(localStorage.terminalMinimized && localStorage.terminalMinimized === "true"){
minimizeTerminal(true);
}
function print(string){
myTerminal.print(string);
}
function handleTerminalInput(inputString) {
// show clearly that it was a command that was typed, not terminal output
let lastLine = document.querySelector("#terminal div > p:nth-child(1) > div:last-child");
lastLine.innerHTML = "> " + lastLine.innerHTML;
argv = inputString.split(' ');
if(argv[0][0] === '/'){
if(slaveLogin && slaveLogin.name && slaveLogin.pass){
print('Running: '+inputString);
} else {
print('Not identified to communicate with any slave! Run "help" for more information.');
}
} else if(argv[0] === 'help'){
if(argv[1] === 'login'){
print('To send commands to a slave, you are required to identify yourself. You can do this with the login command. The name will be the name of the slave as displayed on master. The password is the rcon password of the slave, as per /instances/[name]/config.json');
} else if(argv[1] === "/c"){
print('To run a command, start with /. You can for example do /c game.print("hello world!")');
} else if(argv[1] === "issues"){
print("Issues are reported to clusterio on github or espernet IRC.");
print(" - http://github.com/clusterio/factorioClusterio/issues");
print(" - EsperNet #factorio Danielv123");
} else {
print('To identify yourself to a slave, use "login [name] [password]"');
print(' - /c [command] - Run command');
print(' - login [name] [passs] - Connect to remote slave');
print(' - issues - Report an issue');
}
} else if(argv[0] === 'issues'){
print("Issues are reported to clusterio on github or espernet IRC.");
print(" - http://github.com/clusterio/factorioClusterio/issues");
print(" - EsperNet #factorio Danielv123");
} else {
print('Invalid command!');
}
// keep handling input (unless something is seriously wrong)
myTerminal.input('',handleTerminalInput);
}
}
function minimizeTerminal(instant){
localStorage.terminalMinimized = true;
$('#terminal').draggable('disable');
if(!instant){
$('#terminal')[0].style.transition = 'left 0.2s linear, top 0.2s linear';
}
document.querySelector('.Terminal').style.height = 0;
let ter = $('#terminal')[0];
// if the window just spawned in and we are doing the first minimize, our position won't be set yet. We also don't want to save this blank position.
if(ter.style.left && ter.style.top){
localStorage.oldTerminalPosition = JSON.stringify({x:ter.style.left, y:ter.style.top});
}
ter.style.left = (window.innerWidth - ter.offsetWidth)+'px';
ter.style.top = (window.innerHeight - 25)+'px';
// if we did it instant we still want to set this property for after.
if(instant){
setTimeout(() => $('#terminal')[0].style.transition = 'left 0.2s linear, top 0.2s linear',200);
}
}
function maximizeTerminal(instant){
localStorage.terminalMinimized = false;
document.querySelector('.Terminal').style.height = '400px';
let ter = $('#terminal')[0];
// recover our old saved position
let oldTerminalPosition = JSON.parse(localStorage.oldTerminalPosition);
ter.style.left = oldTerminalPosition.x;
ter.style.top = oldTerminalPosition.y;
// remove our animation once its finished
// since instant is a true/false value, Number will convert it to 1 or 0. Since 0 is falsy, || will turn it into 200.
setTimeout(() => $('#terminal')[0].style.transition = 'none', (Number(instant) || 200));
$('#terminal').draggable('enable');
}
-35
View File
@@ -1,35 +0,0 @@
if(localStorage.settings) {
let settings = JSON.parse(localStorage.settings);
let HTML = "";
for(let key in settings) {
HTML += drawSetting(key, settings[key]);
}
document.querySelector("#body").innerHTML = document.querySelector("#body").innerHTML + HTML;
}
window.onload = function(){
// loop through all settings and add onclick events for them
let sliders = document.querySelectorAll(".settings-box .switch .slider");
for(let i = 0; i < sliders.length; i++) {
sliders[i].onclick = function() {
let settings = JSON.parse(localStorage.settings);
let selectedSliderParent = $(this.parentElement.parentElement);
// walk through DOM structure created by drawSetting and update localstorage from that
console.log(selectedSliderParent.find('.settings-text').html() + " = " + (selectedSliderParent.find("label input").val() === 'on'));
settings[selectedSliderParent.find('.settings-text').html()] = (selectedSliderParent.find("label input").val() === 'on');
localStorage.settings = JSON.stringify(settings);
}
}
};
function drawSetting(settingText, checked) {
let HTML = '<div class="settings-box">' +
'<label class="switch"><input type="checkbox" checked="' + checked + '"' +
'><div class="slider round"></div></label><span class="settings-text ml-3 align-middle">' + settingText + '</span></div>';
return HTML;
}
-88
View File
@@ -1,88 +0,0 @@
nav {
background-color: #25272a;
}
nav li {
height: 80px;
vertical-align: middle;
}
.navbar .nav-title {
font-family: 'Orbitron', sans-serif;
font-size: 25px;
display: inline-block;
vertical-align: bottom;
}
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.settingsBox {
position: relative;
display: block;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #ab671e;
}
input:focus + .slider {
box-shadow: 0 0 1px #ab671e;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.item-unknown-item {
background: url("pictures/unknown-item.png");
height: 32px;
width: 32px;
}
-14
View File
@@ -30,19 +30,6 @@ const masterInventoryGauge = new prometheus.Gauge(
class MasterPlugin extends plugin.BaseMasterPlugin {
async init() {
let externalAddress = this.master.config.get("master.external_address");
let root = externalAddress ? new URL(externalAddress).pathname : "/";
this.ui = {
sidebar: [
{
getHtml: () => `
<div class="nav-item mr-1">
<a class="nav-link align-middle" href="${root}subspace_storage/storage">Storage</a>
</div>`,
},
],
};
this.items = await loadDatabase(this.master.config);
this.itemsLastUpdate = new Map(this.items._items.entries());
this.autosaveId = setInterval(() => {
@@ -61,7 +48,6 @@ class MasterPlugin extends plugin.BaseMasterPlugin {
}, 1000);
routes.addApiRoutes(this.master.app, this.items, this.metrics.endpointHitCounter);
routes.addWebRoutes(this.master.app);
}
updateStorage() {
-6
View File
@@ -5,11 +5,6 @@ const path = require("path");
const prometheus = require("@clusterio/lib/prometheus");
function addWebRoutes(app) {
app.use("/subspace_storage", express.static(path.join(__dirname, "static")));
app.get("/subspace_storage/storage", (req, res) => { res.render("subspace_storage/views/storage"); });
}
function addApiRoutes(app, items, endpointHitCounter) {
/**
@@ -52,6 +47,5 @@ function addApiRoutes(app, items, endpointHitCounter) {
}
module.exports = {
addWebRoutes,
addApiRoutes,
};
@@ -1,99 +0,0 @@
// function to draw data we recieve from ajax requests
"use strict";
var _lastData = [];
function drawcontents(data) {
data = data || _lastData; //Cache data so we can drawcontents without waiting for the server, for the search box.
_lastData = data;
// allow searching for multiple criteria separated by space
var searchArgs = document.querySelector("#search").value;
searchArgs = searchArgs.trim();
searchArgs = "(" + searchArgs.replace(/ +/g,")|(") + ")";
const search = new RegExp(searchArgs, "i");
data = data.filter(function(item) {
return search.test(item.name);
});
sortByKey(data, "count");
const table = document.querySelector("#contents tbody"); //tables have tbody inserted automatically
const rows = table.children;
//update existing rows or create new ones
data.forEach(function(item, i) {
// format count to have .s in it for large number readability (1,000,000)
item.count = item.count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
let row = rows[i];
if(!row) {
row = document.createElement("tr");
row.innerHTML = "<td><div></div></td><td class=name></td><td class=count></td>";
table.appendChild(row);
}
const itemIcon = row.querySelector("div");
const iconClass = getItemIconClass(item.name);
if (itemIcon.getAttribute("class") !== iconClass) {
itemIcon.setAttribute("class", iconClass);
}
let localeName = item.name;
let meta = factorioItemMetadata.get(item.name);
if (meta && meta.localised_name) {
// TODO implement the locale to name conversion.
localeName = factorioLocale.get(meta.localised_name[0]);
} else {
for (let section of ["item-name", "entity-name", "fluid-name", "equipment-name"]) {
let name = factorioLocale.get(`${section}.${item.name}`);
if (name) {
localeName = name;
break;
}
}
}
const name = row.querySelector(".name");
if(name.textContent !== localeName) {
name.textContent = localeName;
}
const count = row.querySelector(".count");
if(count.textContent !== String(item.count)) {
count.textContent = item.count;
}
});
//remove excess rows, for example, after filtering
while (data.length < rows.length) {
table.removeChild(rows[data.length]);
}
}
// get cluster inventory from master
function updateInventory() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let data = JSON.parse(xmlhttp.responseText);
drawcontents(data);
}
};
xmlhttp.open("GET", `${root}api/inventory`, true);
xmlhttp.send();
}
if(JSON.parse(localStorage.settings)["Periodically update storage screen"]) {
setInterval(updateInventory, 500);
} else {
updateInventory();
}
// function to sort arrays of objects after a keys value
function sortByKey(array, key) {
array.sort(function(a, b) {
return b[key] - a[key];
});
}
document.querySelector("#search").addEventListener("input", function() {
drawcontents();
});
@@ -1,41 +0,0 @@
<!doctype HTML>
<head>
<%- include("head") %>
<script defer src="<%= locals.root %>subspace_storage/storage.js"></script>
</head>
<body>
<%- include("nav") %>
<div id="body" class="container">
<div id="storage">
<div class="page-header mt-2 row" id="banner">
<div class="row">
<div class="col-lg-8 col-md-7 col-sm-6">
<h2>Storage</h2>
</div>
</div>
</div>
<div class="form-group mt-3 mb-3 row">
<input type="text" class="form-control" id="search" placeholder="search">
</div>
<div id="contents" class="row w-100">
<table class="table table-striped table-hover">
<thead class="thead-dark">
<tr>
<th scope="col">Icon</th>
<th scope="col">Resource</th>
<th scope="col">Quantity</th>
</tr>
</thead>
<tbody><!-- populated by js --></tbody>
</table>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
crossorigin="anonymous"></script>
</body>
-20
View File
@@ -2,8 +2,6 @@
const assert = require("assert").strict;
const fs = require("fs-extra");
const path = require("path");
const validateHTML = require("html5-validator");
const parallel = require("mocha.parallel");
const link = require("@clusterio/lib/link");
@@ -11,24 +9,6 @@ const { slowTest, get, execCtl, sendRcon, getControl, instancesDir } = require("
describe("Integration of Clusterio", function() {
parallel("master web interface", function() {
this.timeout(6000);
let paths = ["/", "/nodes", "/settings", "/nodeDetails"];
for (let path of paths) {
it(`sends some HTML when accessing ${path}`, async function() {
let res = await get(path);
let validation = await validateHTML(res.body.toString());
let filtered = validation.messages.filter(msg => msg.type !== "info");
assert(
filtered.length === 0,
"there are HTML errors on the page, please fix: "+JSON.stringify(validation.messages, null, 4)
);
});
}
});
describe("clusterioctl", function() {
describe("slave list", function() {
it("runs", async function() {
-5
View File
@@ -1,5 +0,0 @@
// These are libraries that does not have any units test, they are
// required here in order to track coverage for them.
"use strict";
require("@clusterio/master/npm_post_install.js");
-29
View File
@@ -1,29 +0,0 @@
<title>Clusterio</title>
<link rel="stylesheet" type="text/css" href="<%= locals.root %>style.css">
<script>root = "<%= locals.root %>";</script>
<script src="<%= locals.root %>external/jquery.js"></script>
<script src="<%= locals.root %>external/jquery-ui.js"></script>
<script src="<%= locals.root %>external/moment.min.js"></script>
<script src="<%= locals.root %>external/mousetrap.min.js"></script>
<script src="<%= locals.root %>main.js"></script>
<link href="<%= locals.root %>bootstrap.min.css" rel="stylesheet">
<link href="<%= locals.root %>external/css/Roboto.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Orbitron" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.0/css/all.css" integrity="sha384-aOkxzJ5uQz7WBObEZcHvV5JvRW3TUc2rNPA7pe3AwnsUohiw1Vj2Rgx2KSOkF5+h" crossorigin="anonymous">
<link rel="apple-touch-icon" sizes="57x57" href="/favicon/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/favicon/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/favicon/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/favicon/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/favicon/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/favicon/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/favicon/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/favicon/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
<link rel="manifest" href="/favicon/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
-17
View File
@@ -1,17 +0,0 @@
<!doctype HTML>
<head>
<%- include("head") %>
</head>
<body>
<%- include("nav") %>
<div id="body" class="container">
<div id="storage">
<div class="page-header mt-2 row" id="banner">
<div class="row">
<h2>Work in progress interface</h2>
</div>
</div>
</div>
</div>
</body>
-29
View File
@@ -1,29 +0,0 @@
<nav class="navbar nav-pills nav-fill">
<div class="nav-item col-3">
<a class="navbar-brand border-0" href="/">
<img src="<%= locals.root %>pictures/logo.png" width="50" height="50" class="d-inline-block align-middle " alt=""/>
<h3 class=" ml-3 nav-title">Clusterio</h3>
</a>
</div>
<div class="nav-item mr-1">
<a class="nav-link align-middle" href="<%= locals.root %>nodes">Slaves</a>
</div><%
for (let plug of locals.masterPlugins.values()) {
if (
plug
&& plug.ui
&& typeof plug.ui.sidebar == "object"
&& Array.isArray(plug.ui.sidebar)
) {
let sidebarEntries = plug.ui.sidebar;
for (let button of sidebarEntries) {
if (button.getHtml && typeof button.getHtml == "function") { %>
<%- button.getHtml() %><%
}
}
}
} %>
<div class="nav-item">
<a class="nav-link align-middle" href="<%= locals.root %>settings">Settings</a>
</div>
</nav>
-32
View File
@@ -1,32 +0,0 @@
<!doctype HTML>
<head>
<%- include("head") %>
<script src="lib/terminal.js"></script>
<script src="nodeDetails.js"></script>
<link rel="stylesheet" type="text/css" href="nodeDetails.css">
</head>
<body>
<%- include("nav") %>
<div id="body" class="container">
<div id="hero">
<div id="display">
</div>
</div>
<div id="details">
</div>
<div id="terminal">
<div class="titleBar" style="display:none;">
<div class="title">
<p>Clusterio RCON shell</p>
</div>
<div class="titleButton close" onclick="minimizeTerminal();"></div>
<div class="titleButton maximize" onclick="maximizeTerminal();"></div>
<div class="titleButton minimize" onclick="minimizeTerminal();"></div>
</div>
<!-- JS generates a div called .Terminal that appears here with the display and typing things -->
</div>
</div>
</body>
-47
View File
@@ -1,47 +0,0 @@
<!doctype HTML>
<head>
<%- include("head") %>
</head>
<body>
<%- include("nav") %>
<div id="body" class="container">
<div class="page-header mt-2 row" id="banner">
<div class="col-lg-8 col-md-7 col-sm-6">
<h2>Connected Nodes</h2>
</div>
</div>
<div id="display"><%
for (let [id, slave] of locals.slaves) { %>
<div id="<%= id %>" class="slaveBox card mb-3">
<div class="card-body">
<h5 class="card-title"><a href='nodeDetails?instanceID=<%=id%>'>
<%= slave.name %>
</a></h5>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">ID: <%= id %></li>
</ul><%
for (let plug of locals.masterPlugins.values()) {
if (
plug
&& plug.ui
&& typeof plug.ui.slaveListing == "object"
&& Array.isArray(plug.ui.slaveListing)
) {
let slaveListingEntries = plug.ui.slaveListing;
for (let button of slaveListingEntries) {
if (button.getHtml && typeof button.getHtml == "function") { %>
<div class="plugin-link"><%- button.getHtml({slave}) %></div><%
}
}
}
} %>
</div><%
} %>
</div>
</div>
<script>
$('.plugin-link a').addClass('btn btn-primary')
</script>
</body>
-19
View File
@@ -1,19 +0,0 @@
<!doctype HTML>
<head>
<%- include("head") %>
</head>
<body>
<%- include("nav") %>
<div id="body" class="container">
<div class="page-header mt-2 row" id="banner">
<div class="row">
<div class="col-lg-8 col-md-7 col-sm-6">
<h2>Settings</h2>
</div>
</div>
</div>
</div>
<script src="settings.js"></script>
</body>
-1
View File
@@ -1 +0,0 @@
<%- include("nav") %>