Initial commit

This commit is contained in:
2025-10-22 22:06:16 +02:00
commit d8ca4e154f
141 changed files with 32231 additions and 0 deletions

View File

@@ -0,0 +1,192 @@
import { MorphFeature } from 'morphux';
import { Main } from './main';
import {
formatUptime,
ServiceState,
setStatusState,
StatusType,
} from './utils';
const CELCIUS = 'ºC';
export class DashboardCameraRunner {
private _Main: Main;
container: HTMLDivElement = document.querySelector(
'.ntsh_dashboard-camerarunner'
);
connectionStatus: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-connectionstatus'
);
connectionInfo: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-connectioninfo'
);
rebootButton: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-reboot'
);
processStatus: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-processstatus'
);
processInfo: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-processinfo'
);
restartButton: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-restart'
);
uptimeInfo: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-uptime'
);
errorContainer: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-error'
);
errorText: HTMLDivElement = this.container.querySelector(
'.ntsh_dashboard-camerarunner-errortext'
);
constructor(Main: Main) {
this._Main = Main;
this.registerListeners();
}
updateState(state: CameraRunnerStatus) {
// ----------- Connection -----------
setStatusState(
this.connectionStatus,
{
CONNECTING: 'yellow',
CONNECTED: 'green',
DISCONNECTED: 'red',
FAILED: 'red',
}[state.state] as StatusType
);
this.connectionInfo.innerText = state.message ?? '';
// ----------- Process -----------
if (state.state != 'CONNECTED') {
state.processStatus.state = 'STOPPED';
state.processStatus.message = 'Not connected';
state.processStatus.startTime = -1;
this.restartButton.style.display = 'none';
this.rebootButton.style.display = 'none';
} else {
this.rebootButton.style.display = 'flex';
if (state.processStatus.state == 'RUNNING')
this.restartButton.style.display = 'flex';
else this.restartButton.style.display = 'none';
}
setStatusState(
this.processStatus,
{
RUNNING: 'green',
STOPPED: 'gray',
STARTING: 'yellow',
PROBLEM: 'red',
}[state.processStatus.state] as StatusType
);
this.processInfo.innerText = state.processStatus.message ?? '';
// ----------- Uptime -----------
const uptimeSeconds =
state.processStatus.startTime == -1
? -1
: (Date.now() - state.processStatus.startTime) / 1000;
this.uptimeInfo.innerText = formatUptime(uptimeSeconds);
// ----------- Error -----------
const errors: string[] = [];
if ((state?.error ?? '').trim().length > 0) errors.push(state.error);
if ((state?.processStatus?.error ?? '').trim().length > 0)
errors.push(state.processStatus.error);
if (errors.length > 0) {
this.errorText.innerText = errors.join('\n');
this.errorContainer.style.display = 'block';
} else {
this.errorContainer.style.display = 'none';
this.errorText.innerText = '';
}
this._Main.Logs.setCameraLogs(state.processStatus.output.current);
}
registerListeners() {
this._Main.socket.on(
'cameraRunnerState',
(state: CameraRunnerStatus) => {
this.updateState(state);
}
);
this.restartButton.addEventListener('click', async () => {
this.executeCommand(
'restart',
'Are you sure you want to restart the Camera Runner process?'
);
});
this.rebootButton.addEventListener('click', async () => {
this.executeCommand(
'reboot',
'Are you sure you want to reboot the Camera Runner machine?'
);
});
}
private async executeCommand(command: string, message: string) {
const confirmed = await MorphFeature.Confirm({
title: 'Are you sure?',
message,
});
if (!confirmed) return;
MorphFeature.Loader({
active: true,
message: `Requesting Camera Runner ${command}...`,
});
this._Main.socket.emit(
'cameraRunner',
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: `Camera Runner is ${command}ing...`,
});
}
);
}
}
interface CameraRunnerStatus {
state: ServiceState;
message?: string;
error?: string;
processStatus: ProcessStatus;
}
export type ProcessStatusState = 'RUNNING' | 'STOPPED' | 'STARTING' | 'PROBLEM';
interface ProcessStatusSimple {
state: ProcessStatusState;
message?: string;
error?: string;
}
interface ProcessStatus extends ProcessStatusSimple {
startTime: number;
output: { current: string[]; last: string[] };
}