Added basic control panel

This commit is contained in:
2026-03-11 16:46:06 +01:00
parent 7df210aaf2
commit c4eedfff1e
105 changed files with 21923 additions and 958 deletions

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Calibration = void 0;
var Calibration = /** @class */ (function () {
function Calibration(Main) {
this.visible = false;
this.container = document.querySelector('.ntsh-calibration');
this.image = this.container.querySelector('img');
this._Main = Main;
this.registerListeners();
this.startClock();
}
Calibration.prototype.startClock = function () {
var _this = this;
setInterval(function () {
if (_this.visible && _this.image)
_this.image.src = "/calibrationImage?t=".concat(Date.now());
}, 1000);
};
Calibration.prototype.registerListeners = function () {
var _this = this;
this.observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
_this.visible = true;
console.log('Calibration visible');
}
else {
_this.visible = false;
console.log('Calibration not visible');
}
});
});
this.observer.observe(this.container);
};
return Calibration;
}());
exports.Calibration = Calibration;
//# sourceMappingURL=calibration.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"calibration.js","sourceRoot":"","sources":["../ts/calibration.ts"],"names":[],"mappings":";;;AAEA;IASC,qBAAY,IAAU;QALtB,YAAO,GAAY,KAAK,CAAC;QAEzB,cAAS,GAAmB,QAAQ,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC;QACxE,UAAK,GAAqB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAG7D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzB,IAAI,CAAC,UAAU,EAAE,CAAC;IACnB,CAAC;IAEO,gCAAU,GAAlB;QAAA,iBAKC;QAJA,WAAW,CAAC;YACX,IAAI,KAAI,CAAC,OAAO,IAAI,KAAI,CAAC,KAAK;gBAC7B,KAAI,CAAC,KAAK,CAAC,GAAG,GAAG,8BAAuB,IAAI,CAAC,GAAG,EAAE,CAAE,CAAC;QACvD,CAAC,EAAE,IAAI,CAAC,CAAC;IACV,CAAC;IAEO,uCAAiB,GAAzB;QAAA,iBAaC;QAZA,IAAI,CAAC,QAAQ,GAAG,IAAI,oBAAoB,CAAC,UAAC,OAAO;YAChD,OAAO,CAAC,OAAO,CAAC,UAAC,KAAK;gBACrB,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;oBAC1B,KAAI,CAAC,OAAO,GAAG,IAAI,CAAC;oBACpB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;gBACpC,CAAC;qBAAM,CAAC;oBACP,KAAI,CAAC,OAAO,GAAG,KAAK,CAAC;oBACrB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;gBACxC,CAAC;YACF,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IACF,kBAAC;AAAD,CAAC,AAtCD,IAsCC;AAtCY,kCAAW"}

View File

@@ -0,0 +1,96 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Checklist = void 0;
var morphux_1 = require("morphux");
var Checklist = /** @class */ (function () {
function Checklist(Main) {
this.Rows = {
CAMERAPC: document.querySelector(".ntsh-checklist-row[status=\"CAMERAPC\"]"),
CAMERAPROCESS: document.querySelector(".ntsh-checklist-row[status=\"CAMERAPROCESS\"]"),
CAMERAUNITYSTREAM: document.querySelector(".ntsh-checklist-row[status=\"CAMERAUNITYSTREAM\"]"),
UNITYBUILD: document.querySelector(".ntsh-checklist-row[status=\"UNITYBUILD\"]"),
REPLAYFUNCTION: document.querySelector(".ntsh-checklist-row[status=\"REPLAYFUNCTION\"]"),
};
this.FullReboot = document.querySelector('.ntsh-fullreboot-button');
this._Main = Main;
this.registerListeners();
}
Checklist.prototype.update = function (status) {
this.updateRow(this.Rows.CAMERAPC, status.CAMERAPC);
this.updateRow(this.Rows.CAMERAPROCESS, status.CAMERAPROCESS);
this.updateRow(this.Rows.CAMERAUNITYSTREAM, status.CAMERAUNITYSTREAM);
this.updateRow(this.Rows.UNITYBUILD, status.UNITYBUILD);
this.updateRow(this.Rows.REPLAYFUNCTION, status.REPLAYFUNCTION);
console.log('Updated checklist:', status);
};
Checklist.prototype.updateRow = function (row, state) {
var _a, _b, _c;
var status = row.querySelector('.ntsh-checklist-row-status');
var message = row.querySelector('p');
var startButton = row.querySelector('.ntsh-checklist-row-button.start');
var stopButton = row.querySelector('.ntsh-checklist-row-button.stop');
var rebootButton = row.querySelector('.ntsh-checklist-row-button.reboot');
status.classList.remove('RED', 'GREEN', 'YELLOW', 'GRAY');
status.classList.add(state.state);
message.innerText = state.message;
startButton.style.display = ((_a = state.buttons) === null || _a === void 0 ? void 0 : _a.start) ? 'block' : 'none';
stopButton.style.display = ((_b = state.buttons) === null || _b === void 0 ? void 0 : _b.stop) ? 'block' : 'none';
rebootButton.style.display = ((_c = state.buttons) === null || _c === void 0 ? void 0 : _c.reboot) ? 'block' : 'none';
};
Checklist.prototype.registerListeners = function () {
var _this = this;
this.FullReboot.onclick = function () {
morphux_1.MorphFeature.Confirm({
title: 'Full Reboot',
message: 'Are you sure you want to perform a full reboot?',
}, function (state) {
if (!state)
return;
_this._Main.socket.emit('status', 'fullreboot');
});
};
var _loop_1 = function (key) {
var row = this_1.Rows[key];
var startButton = row.querySelector('.ntsh-checklist-row-button.start');
startButton.onclick = function () {
return morphux_1.MorphFeature.Confirm({
title: 'Start',
message: 'Are you sure you want to start?',
}, function (state) {
if (!state)
return;
_this._Main.socket.emit('status', 'start', key);
});
};
var stopButton = row.querySelector('.ntsh-checklist-row-button.stop');
stopButton.onclick = function () {
return morphux_1.MorphFeature.Confirm({
title: 'Stop',
message: 'Are you sure you want to stop?',
}, function (state) {
if (!state)
return;
_this._Main.socket.emit('status', 'stop', key);
});
};
var rebootButton = row.querySelector('.ntsh-checklist-row-button.reboot');
rebootButton.onclick = function () {
return morphux_1.MorphFeature.Confirm({
title: 'Reboot',
message: 'Are you sure you want to reboot?',
}, function (state) {
if (!state)
return;
_this._Main.socket.emit('status', 'reboot', key);
});
};
};
var this_1 = this;
for (var key in this.Rows) {
_loop_1(key);
}
};
return Checklist;
}());
exports.Checklist = Checklist;
//# sourceMappingURL=checklist.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"checklist.js","sourceRoot":"","sources":["../ts/checklist.ts"],"names":[],"mappings":"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"}

144
frontend/views/control/dist/main.js vendored Normal file
View File

@@ -0,0 +1,144 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Main = void 0;
var socket_io_client_1 = require("socket.io-client");
var menu_1 = require("./menu");
var checklist_1 = require("./checklist");
var calibration_1 = require("./calibration");
var morphux_1 = require("morphux");
var outOfServiceMode_1 = require("./outOfServiceMode");
var timer_1 = require("./timer");
var socket = (0, socket_io_client_1.io)('/');
var Main = /** @class */ (function () {
function Main() {
this.Menu = new menu_1.Menu();
this.CheckList = new checklist_1.Checklist(this);
this.Calibration = new calibration_1.Calibration(this);
this.OutOfServiceMode = new outOfServiceMode_1.OutOfServiceMode(this);
this.Timer = new timer_1.Timer(this);
this.socket = socket;
this.supportButton = document.querySelector('.ntsh-support img');
this.supportNumber = '';
this.registerListeners();
}
Main.prototype.registerListeners = function () {
var _this = this;
this.supportButton.onclick = function () { return _this.showSupport(); };
socket.on('status', function (data) {
_this.CheckList.update(data);
});
socket.on('supportNumber', function (number) {
_this.supportNumber = number;
});
socket.on('unityWebSocketState', function (state) {
var _a, _b, _c, _d;
_this.OutOfServiceMode.input.checked =
(_b = (_a = state === null || state === void 0 ? void 0 : state.parameters) === null || _a === void 0 ? void 0 : _a.outOfService) !== null && _b !== void 0 ? _b : false;
_this.OutOfServiceMode.state =
(_d = (_c = state === null || state === void 0 ? void 0 : state.parameters) === null || _c === void 0 ? void 0 : _c.outOfService) !== null && _d !== void 0 ? _d : false;
});
socket.on('timer', function (data) {
_this.Timer.update(data);
});
};
Main.prototype.executeCommand = function (command, message, type) {
if (type === void 0) { type = 'unityRunner'; }
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var confirmed;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, morphux_1.MorphFeature.Confirm({
title: 'Are you sure?',
message: message,
})];
case 1:
confirmed = _a.sent();
if (!confirmed)
return [2 /*return*/, resolve(false)];
morphux_1.MorphFeature.Loader({
active: true,
message: "Dispatching command...",
});
socket.emit(type, command, function (response) {
morphux_1.MorphFeature.Loader({ active: false });
if (!response.succeed)
return morphux_1.MorphFeature.Alert({
title: 'Error',
message: response.message,
});
morphux_1.MorphFeature.Notification({
level: 'success',
message: "Dispatched command",
});
});
resolve(true);
return [2 /*return*/];
}
});
}); })];
});
});
};
Main.prototype.showSupport = function () {
return __awaiter(this, void 0, void 0, function () {
var dialog, callAnchor;
return __generator(this, function (_a) {
dialog = new morphux_1.MorphComponent.Dialog({
title: 'Contact Support',
width: 'medium',
height: 'auto',
okButtonVisible: false,
cancelButtonVisible: false,
});
this.supportNumber.slice();
callAnchor = (0, morphux_1.ce)('a', 'ntsh_callanchor', { href: "tel:".concat(this.supportNumber) }, "+".concat(this.supportNumber));
dialog.content.appendChild(callAnchor);
setTimeout(function () { return callAnchor.click(); }, 100);
return [2 /*return*/];
});
});
};
return Main;
}());
exports.Main = Main;
var _Main = new Main();
//# sourceMappingURL=main.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../ts/main.ts"],"names":[],"mappings":"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"}

46
frontend/views/control/dist/menu.js vendored Normal file
View File

@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Menu = void 0;
var Menu = /** @class */ (function () {
function Menu() {
this.menuContainer = document.querySelector('.ntsh_menubar');
this.tabContainer = document.querySelector('.ntsh_tabs');
this.registerListeners();
if (window.location.search.includes('advanced'))
this.selectTab('advanced');
}
Menu.prototype.selectTab = function (tabId) {
this.menuContainer
.querySelectorAll('.ntsh_menubar-item')
.forEach(function (item) {
if (item.getAttribute('tabid') === tabId) {
item.classList.add('selected');
}
else {
item.classList.remove('selected');
}
});
this.tabContainer.querySelectorAll('.ntsh_tab').forEach(function (tab) {
if (tab.getAttribute('tabid') === tabId) {
tab.classList.add('visible');
}
else {
tab.classList.remove('visible');
}
});
};
Menu.prototype.registerListeners = function () {
var _this = this;
this.menuContainer
.querySelectorAll('.ntsh_menubar-item')
.forEach(function (item) {
item.addEventListener('click', function () {
var itemId = item.getAttribute('tabid');
_this.selectTab(itemId);
});
});
};
return Menu;
}());
exports.Menu = Menu;
//# sourceMappingURL=menu.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"menu.js","sourceRoot":"","sources":["../ts/menu.ts"],"names":[],"mappings":";;;AAAA;IAIC;QAHA,kBAAa,GAAmB,QAAQ,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;QACxE,iBAAY,GAAmB,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;QAGnE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzB,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC9C,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC7B,CAAC;IAED,wBAAS,GAAT,UAAU,KAAa;QACtB,IAAI,CAAC,aAAa;aAChB,gBAAgB,CAAC,oBAAoB,CAAC;aACtC,OAAO,CAAC,UAAC,IAAI;YACb,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,KAAK,EAAE,CAAC;gBAC1C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACnC,CAAC;QACF,CAAC,CAAC,CAAC;QAEJ,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,UAAC,GAAG;YAC3D,IAAI,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,KAAK,EAAE,CAAC;gBACzC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACP,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACjC,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,gCAAiB,GAAzB;QAAA,iBASC;QARA,IAAI,CAAC,aAAa;aAChB,gBAAgB,CAAC,oBAAoB,CAAC;aACtC,OAAO,CAAC,UAAC,IAAI;YACb,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE;gBAC9B,IAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;gBAC1C,KAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACxB,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IACF,WAAC;AAAD,CAAC,AAzCD,IAyCC;AAzCY,oBAAI"}

View File

@@ -0,0 +1,67 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OutOfServiceMode = void 0;
var OutOfServiceMode = /** @class */ (function () {
function OutOfServiceMode(Main) {
this.state = false;
this.input = document.querySelector('.ntsh-outofservicemode-input');
this._Main = Main;
this.registerListeners();
}
OutOfServiceMode.prototype.registerListeners = function () {
var _this = this;
this.input.addEventListener('change', function () { return __awaiter(_this, void 0, void 0, function () {
var valid;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._Main.executeCommand(this.state ? 'disableOutOfService' : 'enableOutOfService', "Are you sure you want to set the installation to \"".concat(this.state ? 'Out of Service' : 'Operational', "\"?"), 'unityWebSocket')];
case 1:
valid = _a.sent();
if (!valid)
this.input.checked = this.state;
this.state = this.input.checked;
return [2 /*return*/];
}
});
}); });
};
return OutOfServiceMode;
}());
exports.OutOfServiceMode = OutOfServiceMode;
//# sourceMappingURL=outOfServiceMode.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"outOfServiceMode.js","sourceRoot":"","sources":["../ts/outOfServiceMode.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA;IAQC,0BAAY,IAAU;QALtB,UAAK,GAAY,KAAK,CAAC;QACvB,UAAK,GAAqB,QAAQ,CAAC,aAAa,CAC/C,8BAA8B,CAC9B,CAAC;QAGD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC1B,CAAC;IAEO,4CAAiB,GAAzB;QAAA,iBAUC;QATA,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE;;;;4BACvB,qBAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAC5C,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,oBAAoB,EACzD,6DAAqD,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,aAAa,QAAI,EACtG,gBAAgB,CAChB,EAAA;;wBAJK,KAAK,GAAG,SAIb;wBACD,IAAI,CAAC,KAAK;4BAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;wBAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;;;;aAChC,CAAC,CAAC;IACJ,CAAC;IACF,uBAAC;AAAD,CAAC,AAzBD,IAyBC;AAzBY,4CAAgB"}

31
frontend/views/control/dist/timer.js vendored Normal file
View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Timer = void 0;
var Timer = /** @class */ (function () {
function Timer(Main) {
this.startup = document.querySelector('.ntsh-timer-startup');
this.shutdown = document.querySelector('.ntsh-timer-shutdown');
this._Main = Main;
this.registerListeners();
}
Timer.prototype.update = function (data) {
var start = "".concat(data.start.hour.toString().padStart(2, '0'), ":").concat(data.start.minute.toString().padStart(2, '0'));
var end = "".concat(data.end.hour.toString().padStart(2, '0'), ":").concat(data.end.minute.toString().padStart(2, '0'));
this.startup.value = start;
this.shutdown.value = end;
};
Timer.prototype.registerListeners = function () {
var _this = this;
this.startup.onchange = function () {
var _a = _this.startup.value.split(':').map(Number), hour = _a[0], minute = _a[1];
_this._Main.socket.emit('setTimerStart', { hour: hour, minute: minute });
};
this.shutdown.onchange = function () {
var _a = _this.shutdown.value.split(':').map(Number), hour = _a[0], minute = _a[1];
_this._Main.socket.emit('setTimerEnd', { hour: hour, minute: minute });
};
};
return Timer;
}());
exports.Timer = Timer;
//# sourceMappingURL=timer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"timer.js","sourceRoot":"","sources":["../ts/timer.ts"],"names":[],"mappings":";;;AAEA;IAMC,eAAY,IAAU;QAHtB,YAAO,GAAqB,QAAQ,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;QAC1E,aAAQ,GAAqB,QAAQ,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;QAG3E,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC1B,CAAC;IAED,sBAAM,GAAN,UAAO,IAGN;QACA,IAAM,KAAK,GAAG,UAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,cAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC;QAChH,IAAM,GAAG,GAAG,UAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,cAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC;QAE1G,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;IAC3B,CAAC;IAED,iCAAiB,GAAjB;QAAA,iBASC;QARA,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG;YACjB,IAAA,KAAiB,KAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAzD,IAAI,QAAA,EAAE,MAAM,QAA6C,CAAC;YACjE,KAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,IAAI,MAAA,EAAE,MAAM,QAAA,EAAE,CAAC,CAAC;QAC3D,CAAC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG;YAClB,IAAA,KAAiB,KAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAA1D,IAAI,QAAA,EAAE,MAAM,QAA8C,CAAC;YAClE,KAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,MAAA,EAAE,MAAM,QAAA,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC;IACH,CAAC;IACF,YAAC;AAAD,CAAC,AAjCD,IAiCC;AAjCY,sBAAK"}

View File

@@ -0,0 +1,284 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NTSH Control</title>
<link rel="stylesheet" href="/material-symbols/index.css">
<link rel="stylesheet" href="./style.css">
<script defer src="./script.js" defer></script>
<link rel="icon" type="image/png" sizes="32x32" href="/img/cloud_thick.png">
</head>
<body>
<div class="ntsh">
<div class="ntsh-wrapper">
<div class="ntsh-inlay">
<div class="ntsh-topbar">
<div class="ntsh_menubar">
<div class="ntsh_menubar-item selected" tabid="home">
HOME
</div>
<div class="ntsh_menubar-item" tabid="advanced">
ADVANCED
</div>
</div>
<img src="/img/logo.png">
<div class="ntsh-separator"></div>
</div>
<div class="ntsh_tabs">
<div class="ntsh_tab visible" tabid="home">
<h2>1. SYSTEM CHECKLIST</h2>
<h3>
Check if all lights are green.
<br>
If not? Reboot!
</h3>
<div class="ntsh-checklist">
<div class="ntsh-checklist-row" status="CAMERAPC">
<div class="ntsh-checklist-row-status"></div>
<div class="ntsh-checklist-row-text">
<h4>CAMERA PC</h4>
<p>Status...</p>
</div>
<div class="ntsh-checklist-row-buttons">
<div class="ntsh-checklist-row-button start">
START
</div>
<div class="ntsh-checklist-row-button stop">
STOP
</div>
<div class="ntsh-checklist-row-button reboot">
REBOOT
</div>
</div>
</div>
<div class="ntsh-checklist-row" status="CAMERAPROCESS">
<div class="ntsh-checklist-row-status"></div>
<div class="ntsh-checklist-row-text">
<h4>CAMERA PROCESS</h4>
<p>Status...</p>
</div>
<div class="ntsh-checklist-row-buttons">
<div class="ntsh-checklist-row-button start">
START
</div>
<div class="ntsh-checklist-row-button stop">
STOP
</div>
<div class="ntsh-checklist-row-button reboot">
REBOOT
</div>
</div>
</div>
<div class="ntsh-checklist-row" status="CAMERAUNITYSTREAM">
<div class="ntsh-checklist-row-status"></div>
<div class="ntsh-checklist-row-text">
<h4>CAMERA/UNITY STREAM</h4>
<p>Status...</p>
</div>
<div class="ntsh-checklist-row-buttons">
<div class="ntsh-checklist-row-button start">
START
</div>
<div class="ntsh-checklist-row-button stop">
STOP
</div>
<div class="ntsh-checklist-row-button reboot">
REBOOT
</div>
</div>
</div>
<div class="ntsh-checklist-row" status="UNITYBUILD">
<div class="ntsh-checklist-row-status"></div>
<div class="ntsh-checklist-row-text">
<h4>UNITY BUILD</h4>
<p>Status...</p>
</div>
<div class="ntsh-checklist-row-buttons">
<div class="ntsh-checklist-row-button start">
START
</div>
<div class="ntsh-checklist-row-button stop">
STOP
</div>
<div class="ntsh-checklist-row-button reboot">
REBOOT
</div>
</div>
</div>
<div class="ntsh-checklist-row" status="REPLAYFUNCTION">
<div class="ntsh-checklist-row-status"></div>
<div class="ntsh-checklist-row-text">
<h4>REPLAY FUNCTION</h4>
<p>Status...</p>
</div>
<div class="ntsh-checklist-row-buttons">
<div class="ntsh-checklist-row-button start">
START
</div>
<div class="ntsh-checklist-row-button stop">
STOP
</div>
<div class="ntsh-checklist-row-button reboot">
REBOOT
</div>
</div>
</div>
</div>
<div class="ntsh-fullreboot">
<div class="ntsh-fullreboot-button">
FULL REBOOT
</div>
</div>
<div class="ntsh-support">
<p>If reboot doesn't help:</p>
<img src="/img/call.png">
</div>
<div class="ntsh-separator"></div>
<h2>2. CALIBRATION CHECK</h2>
<h3>
Look if the top plate of the installation precisely aligns with the pink rectangle.
<br>
If not? Reposition the physical installation.
</h3>
<div class="ntsh-calibration">
<img src="/calibrationImage">
</div>
<h1 style="margin-bottom:30px;">Thank you for checking! :)</h1>
</div>
<div class="ntsh_tab" tabid="advanced">
<h2>OUT OF SERVICE MODE</h2>
<h3>Display the 'out of service' message and mute the sound.</h3>
<div class="ntsh-outofservicemode">
<h4>OUT OF SERVICE MODE</h4>
<label class="switch">
<input type="checkbox" class="ntsh-outofservicemode-input">
<span class="slider round"></span>
</label>
</div>
<div class="ntsh-separator"></div>
<h2>SET TIMER</h2>
<h3>Please set timer in order to schedule the daily reboot.</h3>
<br>
<h3>Advise: fill in 30 minutes before opening and 30 minutes after closing of exhibition.</h3>
<div class="ntsh-timer">
<div class="ntsh-timer-row">
<h4>Start up</h4>
<input type="time" class="ntsh-timer-startup">
</div>
<div class="ntsh-timer-row">
<h4>Shut down</h4>
<input type="time" class="ntsh-timer-shutdown">
</div>
</div>
<div class="ntsh-separator"></div>
<h2>COLOR SETTINGS</h2>
<h3>If lighting at the exhibition location changes during the day (for example in daylight)</h3>
<div class="ntsh-autolighting">
<h4>AUTO LIGHTING</h4>
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
</div>
<div class="ntsh_lightingsettings-container disabled">
<h3>FIXED LIGHTING SETTINGS</h3>
<div class="ntsh_lightingsettings">
<div class="ntsh_lightingsettings-row">
<h4>Brightness</h4>
<input type="range" min="-100" max="100" value="0">
</div>
<div class="ntsh_lightingsettings-row">
<h4>Gain</h4>
<input type="range" min="-100" max="100" value="0">
</div>
<div class="ntsh_lightingsettings-row">
<h4>White Balance</h4>
<input type="range" min="-100" max="100" value="0">
</div>
</div>
</div>
<div class="ntsh-separator"></div>
<h2>SOUND SETTINGS</h2>
<h3>Adjust sound settings according to acoustics of location. (Take in account changes during
the
day and adjust to an average.)</h3>
<div class="ntsh_soundsettings disabled">
<div class="ntsh_soundsettings-row">
<h4>Volume</h4>
<input type="range" min="0" max="100" value="0">
</div>
<div class="ntsh_soundsettings-row">
<h4>EQ low</h4>
<input type="range" min="-100" max="100" value="0">
</div>
<div class="ntsh_soundsettings-row">
<h4>EQ mid</h4>
<input type="range" min="-100" max="100" value="0">
</div>
<div class="ntsh_soundsettings-row">
<h4>EQ high</h4>
<input type="range" min="-100" max="100" value="0">
</div>
</div>
<div class="ntsh_soundsettings-resetcontainer">
<div class="ntsh_soundsettings-reset">
RESET
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

919
frontend/views/control/package-lock.json generated Normal file
View File

@@ -0,0 +1,919 @@
{
"name": "control",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"license": "ISC",
"dependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.1.0",
"@types/node": "^20.12.8",
"ansi_up": "^6.0.6",
"material-symbols": "^0.17.4",
"morphux": "file:../../../../MorphUX",
"rollup": "^2.79.1",
"rollup-plugin-terser": "^7.0.2",
"socket.io-client": "^4.8.1"
},
"devDependencies": {
"@types/sortablejs": "^1.15.8",
"dts-bundle-generator": "^9.5.1"
}
},
"../../../../MorphUX": {
"name": "morphux",
"version": "2026.3.1",
"license": "ISC",
"dependencies": {
"@egjs/hammerjs": "^2.0.17",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.1.0",
"@types/node": "^20.12.8",
"material-symbols": "^0.17.4",
"rollup": "^2.79.1",
"rollup-plugin-terser": "^7.0.2",
"sortablejs": "^1.2.1"
},
"devDependencies": {
"@types/sortablejs": "^1.15.8",
"dts-bundle-generator": "^9.5.1"
}
},
"node_modules/@babel/code-frame": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dependencies": {
"@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@rollup/plugin-commonjs": {
"version": "25.0.8",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.8.tgz",
"integrity": "sha512-ZEZWTK5n6Qde0to4vS9Mr5x/0UZoqCxPVR9KRUjU4kA2sO7GEUn1fop0DAwpO6z0Nw/kJON9bDmSxdWxO/TT1A==",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"commondir": "^1.0.1",
"estree-walker": "^2.0.2",
"glob": "^8.0.3",
"is-reference": "1.2.1",
"magic-string": "^0.30.3"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.68.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/plugin-json": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz",
"integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==",
"dependencies": {
"@rollup/pluginutils": "^5.1.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/plugin-node-resolve": {
"version": "15.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
"integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"@types/resolve": "1.20.2",
"deepmerge": "^4.2.2",
"is-module": "^1.0.0",
"resolve": "^1.22.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.78.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="
},
"node_modules/@types/node": {
"version": "20.19.37",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz",
"integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@types/resolve": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
},
"node_modules/@types/sortablejs": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.9.tgz",
"integrity": "sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==",
"dev": true
},
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ansi_up": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-6.0.6.tgz",
"integrity": "sha512-yIa1x3Ecf8jWP4UWEunNjqNX6gzE4vg2gGz+xqRGY+TBSucnYp6RRdPV4brmtg6bQ1ljD48mZ5iGSEj7QEpRKA==",
"engines": {
"node": "*"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/dts-bundle-generator": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/dts-bundle-generator/-/dts-bundle-generator-9.5.1.tgz",
"integrity": "sha512-DxpJOb2FNnEyOzMkG11sxO2dmxPjthoVWxfKqWYJ/bI/rT1rvTMktF5EKjAYrRZu6Z6t3NhOUZ0sZ5ZXevOfbA==",
"dev": true,
"dependencies": {
"typescript": ">=5.0.2",
"yargs": "^17.6.0"
},
"bin": {
"dts-bundle-generator": "dist/bin/dts-bundle-generator.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/engine.io-client": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz",
"integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.18.3",
"xmlhttprequest-ssl": "~2.1.1"
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/glob": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^5.0.1",
"once": "^1.3.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="
},
"node_modules/is-reference": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/jest-worker": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
"integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^7.0.0"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/material-symbols": {
"version": "0.17.4",
"resolved": "https://registry.npmjs.org/material-symbols/-/material-symbols-0.17.4.tgz",
"integrity": "sha512-5zI+rSzAidMJxAIrQCVwnp4rMjFnx8aQg68lfFXtaDeksZzJ7m8eDl16y9bRNxMosuYbLKeDHDbOWHPJJTSLhQ=="
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
},
"node_modules/minimatch": {
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/morphux": {
"resolved": "../../../../MorphUX",
"link": true
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/resolve": {
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
"dependencies": {
"is-core-module": "^2.16.1",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/rollup": {
"version": "2.80.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz",
"integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==",
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=10.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/rollup-plugin-terser": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
"integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
"deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser",
"dependencies": {
"@babel/code-frame": "^7.10.4",
"jest-worker": "^26.2.1",
"serialize-javascript": "^4.0.0",
"terser": "^5.0.0"
},
"peerDependencies": {
"rollup": "^2.0.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"dependencies": {
"randombytes": "^2.1.0"
}
},
"node_modules/socket.io-client": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz",
"integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.4.1",
"engine.io-client": "~6.6.1",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz",
"integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.4.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/terser": {
"version": "5.46.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz",
"integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"engines": {
"node": ">=12"
}
}
}
}

View File

@@ -0,0 +1,27 @@
{
"scripts": {
"build": "sass scss/index.scss style.css && tsc && npm run bundle",
"watch-ts": "tsc -w",
"watch-scss": "sass scss/index.scss style.css -w",
"watch-rollup": "rollup -c --watch",
"watch-rebuildscss": "rm style.css && npm run watch-scss"
},
"author": "",
"license": "ISC",
"dependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.1.0",
"@types/node": "^20.12.8",
"ansi_up": "^6.0.6",
"material-symbols": "^0.17.4",
"morphux": "file:../../../../MorphUX",
"rollup": "^2.79.1",
"rollup-plugin-terser": "^7.0.2",
"socket.io-client": "^4.8.1"
},
"devDependencies": {
"@types/sortablejs": "^1.15.8",
"dts-bundle-generator": "^9.5.1"
}
}

View File

@@ -0,0 +1,19 @@
import cjs from '@rollup/plugin-commonjs';
import node from '@rollup/plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';
import json from '@rollup/plugin-json';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'dist/main.js',
output: [
{ file: 'script.js', format: 'iife', sourcemap: true, inlineDynamicImports: true }
],
plugins: [
node({ browser: true }),
cjs(),
production && terser(),
json()
],
};

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,183 @@
.ntsh-outofservicemode {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 20px;
margin-top: 30px;
}
.ntsh-timer {
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 10px;
margin-top: 30px;
.ntsh-timer-row {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 20px;
h4 {
width: 85px;
}
input[type="time"] {
position: relative;
padding: 10px;
border: 2px solid #000;
font-weight: 500;
transition-duration: 0.2s;
cursor: pointer;
font-size: 20px;
&::-webkit-calendar-picker-indicator {
background: transparent;
bottom: 0;
color: transparent;
cursor: pointer;
height: auto;
left: 0;
position: absolute;
right: 0;
top: 0;
width: auto;
}
}
}
}
.ntsh-autolighting {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 20px;
margin: 30px 0px;
}
.ntsh_lightingsettings-container {
width: 100%;
&.disabled {
opacity: .3;
pointer-events: none;
}
h3 {
margin-bottom: 10px;
}
.ntsh_lightingsettings {
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 5px;
.ntsh_lightingsettings-row {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 20px;
h4 {
width: 120px;
}
input {
position: relative;
padding: 10px;
border: 2px solid #000;
font-weight: 500;
transition-duration: 0.2s;
cursor: pointer;
font-size: 20px;
&::-webkit-calendar-picker-indicator {
background: transparent;
bottom: 0;
color: transparent;
cursor: pointer;
height: auto;
left: 0;
position: absolute;
right: 0;
top: 0;
width: auto;
}
}
}
}
}
.ntsh_soundsettings {
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 5px;
&.disabled {
opacity: .3;
pointer-events: none;
}
.ntsh_soundsettings-row {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 20px;
h4 {
width: 120px;
}
input {
padding: 10px;
border: 2px solid #000;
font-weight: 500;
transition-duration: 0.2s;
cursor: pointer;
font-size: 20px;
&::-webkit-calendar-picker-indicator {
background: transparent;
bottom: 0;
color: transparent;
cursor: pointer;
height: auto;
left: 0;
position: absolute;
right: 0;
top: 0;
width: auto;
}
}
}
}
.ntsh_soundsettings-resetcontainer {
width: 100%;
display: flex;
justify-content: flex-end;
margin-bottom: 30px;
.ntsh_soundsettings-reset {
padding: 10px 20px;
border: 2px solid #000;
font-weight: 500;
transition-duration: .2s;
cursor: pointer;
&:hover {
background: #d7ccc1;
}
}
}

View File

@@ -0,0 +1,70 @@
.ntsh-checklist {
width: 100%;
margin: 30px 0px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 10px;
.ntsh-checklist-row {
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
gap: 10px;
.ntsh-checklist-row-status {
width: 20px;
height: 20px;
margin: 0px 10px;
border-radius: 100%;
background: #00000024;
flex-shrink: 0;
&.GREEN {
background: #1db100;
}
&.RED {
background: #b10000;
}
&.YELLOW {
background: #b1a100;
}
&.GRAY {
background: #d5c7ba;
}
}
.ntsh-checklist-row-text {
flex-grow: 1;
}
.ntsh-checklist-row-buttons {
display: flex;
flex-direction: column;
gap: 3px;
.ntsh-checklist-row-button {
align-self: stretch;
display: none;
padding: 5px 10px;
border: 2px solid #000;
font-weight: 500;
transition-duration: 0.2s;
cursor: pointer;
font-size: 12px;
text-align: center;
&:hover {
background: #d7ccc1;
}
}
}
}
}

View File

@@ -0,0 +1,60 @@
.ntsh-fullreboot {
width: 100%;
display: flex;
justify-content: center;
.ntsh-fullreboot-button {
padding: 20px;
border: 2px solid #000;
font-weight: 500;
transition-duration: 0.2s;
cursor: pointer;
background: #ff644e;
font-size: 25px;
font-weight: 800;
letter-spacing: -1px;
&:hover {
background: #be4939;
}
}
}
.ntsh-support {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
margin-top: 30px;
img {
height: 50px;
cursor: pointer;
transition-duration: .2s;
&:hover {
filter: brightness(.8);
}
}
}
.ntsh-calibration {
width: 100%;
margin: 30px 0px;
img {
width: 100%;
}
}
.ntsh_callanchor {
width: 100%;
display: block;
background: #454545;
text-align: center;
padding: 10px 00px;
font-size: 40px;
color: #fff;
}

View File

@@ -0,0 +1,75 @@
@use '../node_modules/morphux/style.css';
@use './topbar.scss';
@use './checklist.scss';
@use './text.scss';
@use './switch.scss';
@use './home.scss';
@use './advanced.scss';
@font-face {
font-family: Roboto;
src: url(/font/Roboto-VariableFont_wdth,wght.ttf) format('truetype');
}
@font-face {
font-family: ScothBrace;
src: url(/font/ScothBrace.ttf) format('truetype');
}
@font-face {
font-family: RidleyGrotesk;
src: url(/font/RidleyGrotesk-Bold.otf) format('opentype');
font-weight: bold;
}
@font-face {
font-family: RidleyGrotesk;
src: url(/font/RidleyGrotesk-Regular.otf) format('opentype');
font-weight: normal;
}
body {
position: absolute;
inset: 0px;
margin: 0px;
padding: 0px;
color: #000;
font-family: RidleyGrotesk, sans-serif;
background: #E1EAF6;
}
.ntsh {
position: absolute;
inset: 0px;
overflow-y: scroll;
.ntsh-wrapper {
width: 100%;
min-height: 100%;
background: linear-gradient(0deg, #E1EAF6, #F9E7D6);
.ntsh-inlay {
width: min(800px, calc(100% - 40px));
margin: 0 auto;
}
}
}
.ntsh_tabs {
width: 100%;
.ntsh_tab {
width: 100%;
display: none;
&.visible {
display: block;
}
}
}
.ntsh-separator {
width: 100%;
border-bottom: 10px dotted #000;
margin: 30px 0px;
}

View File

@@ -0,0 +1,61 @@
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
/* 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: #2bc038;
}
input:focus+.slider {
box-shadow: 0 0 1px #2bc038;
}
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%;
}

View File

@@ -0,0 +1,27 @@
h1 {
font-size: 45px;
margin: 0px;
font-weight: 600;
}
h2 {
font-size: 24px;
margin: 0px 0px 5px 0px;
}
h3 {
font-size: 22px;
margin: 0px;
font-weight: 400;
}
h4 {
font-size: 14px;
margin: 0px;
}
p {
font-size: 14px;
margin: 0px;
}

View File

@@ -0,0 +1,30 @@
.ntsh-topbar {
.ntsh_menubar {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
.ntsh_menubar-item {
padding: 10px 20px;
border: 2px solid #000;
font-weight: 500;
transition-duration: .2s;
cursor: pointer;
&:hover {
background: #d7ccc1;
}
&.selected {
pointer-events: none;
opacity: .3;
}
}
}
img {
width: 100%;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,41 @@
import { Main } from './main';
export class Calibration {
private _Main: Main;
observer: IntersectionObserver;
visible: boolean = false;
container: HTMLDivElement = document.querySelector('.ntsh-calibration');
image: HTMLImageElement = this.container.querySelector('img');
constructor(Main: Main) {
this._Main = Main;
this.registerListeners();
this.startClock();
}
private startClock() {
setInterval(() => {
if (this.visible && this.image)
this.image.src = `/calibrationImage?t=${Date.now()}`;
}, 1000);
}
private registerListeners() {
this.observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
this.visible = true;
console.log('Calibration visible');
} else {
this.visible = false;
console.log('Calibration not visible');
}
});
});
this.observer.observe(this.container);
}
}

View File

@@ -0,0 +1,146 @@
import { Main } from './main';
import { MorphFeature } from 'morphux';
export class Checklist {
private _Main: Main;
Rows = {
CAMERAPC: document.querySelector(
`.ntsh-checklist-row[status="CAMERAPC"]`,
) as HTMLDivElement,
CAMERAPROCESS: document.querySelector(
`.ntsh-checklist-row[status="CAMERAPROCESS"]`,
) as HTMLDivElement,
CAMERAUNITYSTREAM: document.querySelector(
`.ntsh-checklist-row[status="CAMERAUNITYSTREAM"]`,
) as HTMLDivElement,
UNITYBUILD: document.querySelector(
`.ntsh-checklist-row[status="UNITYBUILD"]`,
) as HTMLDivElement,
REPLAYFUNCTION: document.querySelector(
`.ntsh-checklist-row[status="REPLAYFUNCTION"]`,
) as HTMLDivElement,
};
FullReboot: HTMLDivElement = document.querySelector(
'.ntsh-fullreboot-button',
);
constructor(Main: Main) {
this._Main = Main;
this.registerListeners();
}
update(status: Status) {
this.updateRow(this.Rows.CAMERAPC, status.CAMERAPC);
this.updateRow(this.Rows.CAMERAPROCESS, status.CAMERAPROCESS);
this.updateRow(this.Rows.CAMERAUNITYSTREAM, status.CAMERAUNITYSTREAM);
this.updateRow(this.Rows.UNITYBUILD, status.UNITYBUILD);
this.updateRow(this.Rows.REPLAYFUNCTION, status.REPLAYFUNCTION);
console.log('Updated checklist:', status);
}
updateRow(row: HTMLDivElement, state: StateEntry) {
const status: HTMLDivElement = row.querySelector(
'.ntsh-checklist-row-status',
);
const message: HTMLDivElement = row.querySelector('p');
const startButton: HTMLDivElement = row.querySelector(
'.ntsh-checklist-row-button.start',
);
const stopButton: HTMLDivElement = row.querySelector(
'.ntsh-checklist-row-button.stop',
);
const rebootButton: HTMLDivElement = row.querySelector(
'.ntsh-checklist-row-button.reboot',
);
status.classList.remove('RED', 'GREEN', 'YELLOW', 'GRAY');
status.classList.add(state.state);
message.innerText = state.message;
startButton.style.display = state.buttons?.start ? 'block' : 'none';
stopButton.style.display = state.buttons?.stop ? 'block' : 'none';
rebootButton.style.display = state.buttons?.reboot ? 'block' : 'none';
}
private registerListeners() {
this.FullReboot.onclick = () => {
MorphFeature.Confirm(
{
title: 'Full Reboot',
message: 'Are you sure you want to perform a full reboot?',
},
(state) => {
if (!state) return;
this._Main.socket.emit('status', 'fullreboot');
},
);
};
for (const key in this.Rows) {
const row = this.Rows[key];
const startButton: HTMLDivElement = row.querySelector(
'.ntsh-checklist-row-button.start',
);
startButton.onclick = () =>
MorphFeature.Confirm(
{
title: 'Start',
message: 'Are you sure you want to start?',
},
(state) => {
if (!state) return;
this._Main.socket.emit('status', 'start', key);
},
);
const stopButton: HTMLDivElement = row.querySelector(
'.ntsh-checklist-row-button.stop',
);
stopButton.onclick = () =>
MorphFeature.Confirm(
{
title: 'Stop',
message: 'Are you sure you want to stop?',
},
(state) => {
if (!state) return;
this._Main.socket.emit('status', 'stop', key);
},
);
const rebootButton: HTMLDivElement = row.querySelector(
'.ntsh-checklist-row-button.reboot',
);
rebootButton.onclick = () =>
MorphFeature.Confirm(
{
title: 'Reboot',
message: 'Are you sure you want to reboot?',
},
(state) => {
if (!state) return;
this._Main.socket.emit('status', 'reboot', key);
},
);
}
}
}
interface Status {
CAMERAPC: StateEntry;
CAMERAPROCESS: StateEntry;
CAMERAUNITYSTREAM: StateEntry;
UNITYBUILD: StateEntry;
REPLAYFUNCTION: StateEntry;
}
interface StateEntry {
state: 'GREEN' | 'RED' | 'YELLOW' | 'GRAY';
message: string;
buttons?: { reboot?: boolean; start?: boolean; stop?: boolean };
}

View File

@@ -0,0 +1,180 @@
import { io } from 'socket.io-client';
import { Menu } from './menu';
import { Checklist } from './checklist';
import { Calibration } from './calibration';
import { ce, MorphComponent, MorphFeature } from 'morphux';
import { OutOfServiceMode } from './outOfServiceMode';
import { Timer } from './timer';
const socket = io('/');
export class Main {
Menu = new Menu();
CheckList = new Checklist(this);
Calibration = new Calibration(this);
OutOfServiceMode = new OutOfServiceMode(this);
Timer = new Timer(this);
socket = socket;
supportButton: HTMLDivElement = document.querySelector('.ntsh-support img');
supportNumber: string = '';
constructor() {
this.registerListeners();
}
private registerListeners() {
this.supportButton.onclick = () => this.showSupport();
socket.on('status', (data) => {
this.CheckList.update(data);
});
socket.on('supportNumber', (number: string) => {
this.supportNumber = number;
});
socket.on('unityWebSocketState', (state: UnityWebSocketStatus) => {
this.OutOfServiceMode.input.checked =
state?.parameters?.outOfService ?? false;
this.OutOfServiceMode.state =
state?.parameters?.outOfService ?? false;
});
socket.on('timer', (data) => {
this.Timer.update(data);
});
}
async executeCommand(
command: string,
message: string,
type: 'unityRunner' | 'unityWebSocket' = 'unityRunner',
): Promise<boolean> {
return new Promise<boolean>(async (resolve) => {
const confirmed = await MorphFeature.Confirm({
title: 'Are you sure?',
message,
});
if (!confirmed) return resolve(false);
MorphFeature.Loader({
active: true,
message: `Dispatching command...`,
});
socket.emit(
type,
command,
(response: { succeed: boolean; message?: string }) => {
MorphFeature.Loader({ active: false });
if (!response.succeed)
return MorphFeature.Alert({
title: 'Error',
message: response.message,
});
MorphFeature.Notification({
level: 'success',
message: `Dispatched command`,
});
},
);
resolve(true);
});
}
async showSupport() {
const dialog = new MorphComponent.Dialog({
title: 'Contact Support',
width: 'medium',
height: 'auto',
okButtonVisible: false,
cancelButtonVisible: false,
});
this.supportNumber.slice();
const callAnchor = ce(
'a',
'ntsh_callanchor',
{ href: `tel:${this.supportNumber}` },
`+${this.supportNumber}`,
);
dialog.content.appendChild(callAnchor);
setTimeout(() => callAnchor.click(), 100);
}
}
const _Main = new Main();
export type ServiceState =
| 'CONNECTING'
| 'CONNECTED'
| 'DISCONNECTED'
| 'FAILED';
interface UnityWebSocketStatus {
state: ServiceState;
message?: string;
error?: string;
parameters: UnityParameters;
}
interface UnityParameters {
timelineWatching: boolean;
timelineStanding: boolean;
timelineProgress: number;
zedPath: string;
zedReady: boolean;
zedFPS: string;
outOfService: boolean;
sliders: UnityParameterSlider[];
advancedSliders: UnityParameterSlider[];
sensors: UnitySocketMessageHeartbeat['heartbeat']['dataSensors'];
}
type UnityHeartbeatSlider =
UnitySocketMessageHeartbeat['heartbeat']['dataSliders'][number];
interface UnityParameterSlider extends UnityHeartbeatSlider {
visualMultiplier: number;
decimalPlaces: number;
}
interface UnitySocketMessageBase {
type: string;
timestamp: number;
}
interface UnitySocketMessageHeartbeat extends UnitySocketMessageBase {
type: 'heartbeat_data';
heartbeat: {
dataSensors: {
sensorIndex: number;
deviceName: string;
outputValue: number;
}[];
dataSliders: {
sliderIndex: number;
sliderName: string;
outputValue: number;
min: number;
max: number;
unit: string;
}[];
dataTimeline: {
isStanding: boolean;
isWatching: boolean;
timelineProgress: number;
};
zedCamera: {
cameraFPS: string;
isZedReady: boolean;
streamInputIP: string;
streamInputPort: number;
zedGrabError: number;
};
showOutOfService?: boolean;
};
}

View File

@@ -0,0 +1,42 @@
export class Menu {
menuContainer: HTMLDivElement = document.querySelector('.ntsh_menubar');
tabContainer: HTMLDivElement = document.querySelector('.ntsh_tabs');
constructor() {
this.registerListeners();
if (window.location.search.includes('advanced'))
this.selectTab('advanced');
}
selectTab(tabId: string) {
this.menuContainer
.querySelectorAll('.ntsh_menubar-item')
.forEach((item) => {
if (item.getAttribute('tabid') === tabId) {
item.classList.add('selected');
} else {
item.classList.remove('selected');
}
});
this.tabContainer.querySelectorAll('.ntsh_tab').forEach((tab) => {
if (tab.getAttribute('tabid') === tabId) {
tab.classList.add('visible');
} else {
tab.classList.remove('visible');
}
});
}
private registerListeners() {
this.menuContainer
.querySelectorAll('.ntsh_menubar-item')
.forEach((item) => {
item.addEventListener('click', () => {
const itemId = item.getAttribute('tabid');
this.selectTab(itemId);
});
});
}
}

View File

@@ -0,0 +1,29 @@
import { MorphComponent } from 'morphux';
import { Main } from './main';
export class OutOfServiceMode {
private _Main: Main;
state: boolean = false;
input: HTMLInputElement = document.querySelector(
'.ntsh-outofservicemode-input',
);
constructor(Main: Main) {
this._Main = Main;
this.registerListeners();
}
private registerListeners() {
this.input.addEventListener('change', async () => {
const valid = await this._Main.executeCommand(
this.state ? 'disableOutOfService' : 'enableOutOfService',
`Are you sure you want to set the installation to "${this.state ? 'Out of Service' : 'Operational'}"?`,
'unityWebSocket',
);
if (!valid) this.input.checked = this.state;
this.state = this.input.checked;
});
}
}

View File

@@ -0,0 +1,36 @@
import { Main } from './main';
export class Timer {
private _Main: Main;
startup: HTMLInputElement = document.querySelector('.ntsh-timer-startup');
shutdown: HTMLInputElement = document.querySelector('.ntsh-timer-shutdown');
constructor(Main: Main) {
this._Main = Main;
this.registerListeners();
}
update(data: {
start: { hour: number; minute: number };
end: { hour: number; minute: number };
}) {
const start = `${data.start.hour.toString().padStart(2, '0')}:${data.start.minute.toString().padStart(2, '0')}`;
const end = `${data.end.hour.toString().padStart(2, '0')}:${data.end.minute.toString().padStart(2, '0')}`;
this.startup.value = start;
this.shutdown.value = end;
}
registerListeners() {
this.startup.onchange = () => {
const [hour, minute] = this.startup.value.split(':').map(Number);
this._Main.socket.emit('setTimerStart', { hour, minute });
};
this.shutdown.onchange = () => {
const [hour, minute] = this.shutdown.value.split(':').map(Number);
this._Main.socket.emit('setTimerEnd', { hour, minute });
};
}
}

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"outDir": "dist",
"sourceMap": true
},
"include": [
"ts/**/*"
]
}

View File

@@ -7,8 +7,8 @@
<title>NTSH Control</title>
<link rel="stylesheet" href="/material-symbols/index.css">
<link rel="stylesheet" href="./style.css">
<script defer src="./script.js" defer></script>
<link rel="stylesheet" href="/dashboard/style.css">
<script defer src="/dashboard/script.js" defer></script>
<link rel="icon" type="image/png" sizes="32x32" href="/img/cloud_thick.png">
</head>