Initial commit
This commit is contained in:
192
frontend/views/dashboard/ts/dashboard.camerarunner.ts
Normal file
192
frontend/views/dashboard/ts/dashboard.camerarunner.ts
Normal 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[] };
|
||||
}
|
||||
Reference in New Issue
Block a user