refactor: small type improvements (#759)

This commit is contained in:
Carlos Valente
2024-02-03 23:17:36 +01:00
committed by GitHub
parent 1890fc49d7
commit 212e5f9e68
23 changed files with 143 additions and 91 deletions
+2
View File
@@ -27,7 +27,9 @@
"ws": "^8.13.0" "ws": "^8.13.0"
}, },
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/multer": "^1.4.11",
"@types/node": "^18.11.18", "@types/node": "^18.11.18",
"@types/node-osc": "^6.0.2", "@types/node-osc": "^6.0.2",
"@types/websocket": "^1.0.5", "@types/websocket": "^1.0.5",
+3 -3
View File
@@ -25,7 +25,7 @@ import { eventStore } from '../stores/EventStore.js';
import { dispatchFromAdapter } from '../controllers/integrationController.js'; import { dispatchFromAdapter } from '../controllers/integrationController.js';
import { logger } from '../classes/Logger.js'; import { logger } from '../classes/Logger.js';
let instance; let instance: SocketServer | null = null;
export class SocketServer implements IAdapter { export class SocketServer implements IAdapter {
private readonly MAX_PAYLOAD = 1024 * 256; // 256Kb private readonly MAX_PAYLOAD = 1024 * 256; // 256Kb
@@ -50,7 +50,7 @@ export class SocketServer implements IAdapter {
this.wss.on('connection', (ws) => { this.wss.on('connection', (ws) => {
let clientId = getRandomName(); let clientId = getRandomName();
this.clientIds.add(clientId); this.clientIds.add(clientId);
logger.info(LogOrigin.Client, `${this.wss.clients.size} Connections with new: ${clientId}`); logger.info(LogOrigin.Client, `${this.clientIds.size} Connections with new: ${clientId}`);
// send store payload on connect // send store payload on connect
ws.send( ws.send(
@@ -70,8 +70,8 @@ export class SocketServer implements IAdapter {
ws.on('error', console.error); ws.on('error', console.error);
ws.on('close', () => { ws.on('close', () => {
logger.info(LogOrigin.Client, `${this.wss.clients.size} Connections with disconnected: ${clientId}`);
this.clientIds.delete(clientId); this.clientIds.delete(clientId);
logger.info(LogOrigin.Client, `${this.clientIds.size} Connections with disconnected: ${clientId}`);
}); });
ws.on('message', (data) => { ws.on('message', (data) => {
@@ -33,8 +33,8 @@ describe('objectFromPath()', () => {
const obj = objectFromPath(arr); const obj = objectFromPath(arr);
expect(obj).toStrictEqual(objExpected); expect(obj).toStrictEqual(objExpected);
}); });
it('empty array creates undefinde object', () => { it('empty array creates undefined object', () => {
const arr = []; const arr: string[] = [];
const value = '1234567890'; const value = '1234567890';
const objExpected = null; const objExpected = null;
+2 -2
View File
@@ -170,8 +170,8 @@ export const startServer = async () => {
eventNext: state.eventNext, eventNext: state.eventNext,
publicEventNext: state.publicEventNext, publicEventNext: state.publicEventNext,
timer1: { timer1: {
duration: null, duration: 0,
current: null, current: 0,
playback: SimplePlayback.Stop, playback: SimplePlayback.Stop,
direction: SimpleDirection.CountDown, direction: SimpleDirection.CountDown,
}, },
@@ -11,6 +11,7 @@ import {
UserFields, UserFields,
Alias, Alias,
Settings, Settings,
HttpSettings,
} from 'ontime-types'; } from 'ontime-types';
import { data, db } from '../../modules/loadDb.js'; import { data, db } from '../../modules/loadDb.js';
@@ -98,7 +99,7 @@ export class DataProvider {
await this.persist(); await this.persist();
} }
static async setHttp(newData) { static async setHttp(newData: HttpSettings) {
data.http = { ...newData }; data.http = { ...newData };
await this.persist(); await this.persist();
} }
@@ -38,7 +38,8 @@ export class SimpleTimer {
public start(timeNow: number): SimpleTimerState { public start(timeNow: number): SimpleTimerState {
if (this.state.playback === SimplePlayback.Pause) { if (this.state.playback === SimplePlayback.Pause) {
const elapsedSincePause = this.pausedAt - this.startedAt; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know these are not null in a timer that is paused
const elapsedSincePause = this.pausedAt! - this.startedAt!;
this.startedAt = timeNow - elapsedSincePause; this.startedAt = timeNow - elapsedSincePause;
} else if (this.state.playback === SimplePlayback.Stop) { } else if (this.state.playback === SimplePlayback.Stop) {
this.startedAt = timeNow; this.startedAt = timeNow;
+62 -59
View File
@@ -8,7 +8,7 @@ import type {
ErrorResponse, ErrorResponse,
ProjectFileListResponse, ProjectFileListResponse,
} from 'ontime-types'; } from 'ontime-types';
import { deepmerge } from 'ontime-utils'; import { ExcelImportOptions, deepmerge } from 'ontime-utils';
import { RequestHandler, Request, Response } from 'express'; import { RequestHandler, Request, Response } from 'express';
import fs from 'fs'; import fs from 'fs';
@@ -44,7 +44,7 @@ import { removeFileExtension } from '../utils/removeFileExtension.js';
// Create controller for GET request to '/ontime/poll' // Create controller for GET request to '/ontime/poll'
// Returns data for current state // Returns data for current state
export const poll = async (_req, res) => { export const poll = async (_req: Request, res: Response) => {
try { try {
const state = eventStore.poll(); const state = eventStore.poll();
res.status(200).send(state); res.status(200).send(state);
@@ -57,7 +57,7 @@ export const poll = async (_req, res) => {
// Create controller for GET request to '/ontime/db' // Create controller for GET request to '/ontime/db'
// Returns - // Returns -
export const dbDownload = async (req, res) => { export const dbDownload = async (_req: Request, res: Response) => {
const { title } = DataProvider.getProjectData(); const { title } = DataProvider.getProjectData();
const fileTitle = title || 'ontime data'; const fileTitle = title || 'ontime data';
@@ -77,7 +77,7 @@ export const dbDownload = async (req, res) => {
* @param _res * @param _res
* @param options * @param options
*/ */
async function parseFile(file, _req, _res, options) { async function parseFile(file, _req: Request, _res: Response, options: ExcelImportOptions) {
if (!fs.existsSync(file)) { if (!fs.existsSync(file)) {
throw new Error('Upload failed'); throw new Error('Upload failed');
} }
@@ -85,6 +85,10 @@ async function parseFile(file, _req, _res, options) {
return result.data; return result.data;
} }
export type ParsingOptions = {
onlyRundown?: 'true' | 'false';
};
/** /**
* parse an uploaded file and apply its parsed objects * parse an uploaded file and apply its parsed objects
* @param file * @param file
@@ -93,7 +97,7 @@ async function parseFile(file, _req, _res, options) {
* @param [options] * @param [options]
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
const parseAndApply = async (file, _req, res, options) => { const parseAndApply = async (file, _req: Request, res: Response, options) => {
const result = await parseFile(file, _req, res, options); const result = await parseFile(file, _req, res, options);
runtimeService.stop(); runtimeService.stop();
@@ -134,7 +138,7 @@ const getNetworkInterfaces = () => {
// Create controller for GET request to '/ontime/info' // Create controller for GET request to '/ontime/info'
// Returns - // Returns -
export const getInfo = async (req: Request, res: Response<GetInfo>) => { export const getInfo = async (_req: Request, res: Response<GetInfo>) => {
const { version, serverPort } = DataProvider.getSettings(); const { version, serverPort } = DataProvider.getSettings();
const osc = DataProvider.getOsc(); const osc = DataProvider.getOsc();
@@ -155,14 +159,14 @@ export const getInfo = async (req: Request, res: Response<GetInfo>) => {
// Create controller for POST request to '/ontime/aliases' // Create controller for POST request to '/ontime/aliases'
// Returns - // Returns -
export const getAliases = async (req, res) => { export const getAliases = async (_req: Request, res: Response) => {
const aliases = DataProvider.getAliases(); const aliases = DataProvider.getAliases();
res.status(200).send(aliases); res.status(200).send(aliases);
}; };
// Create controller for POST request to '/ontime/aliases' // Create controller for POST request to '/ontime/aliases'
// Returns ACK message // Returns ACK message
export const postAliases = async (req, res) => { export const postAliases = async (req: Request, res: Response) => {
if (failIsNotArray(req.body, res)) { if (failIsNotArray(req.body, res)) {
return; return;
} }
@@ -178,20 +182,20 @@ export const postAliases = async (req, res) => {
await DataProvider.setAliases(newAliases); await DataProvider.setAliases(newAliases);
res.status(200).send(newAliases); res.status(200).send(newAliases);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
// Create controller for GET request to '/ontime/userfields' // Create controller for GET request to '/ontime/userfields'
// Returns - // Returns -
export const getUserFields = async (req, res) => { export const getUserFields = async (_req: Request, res: Response) => {
const userFields = DataProvider.getUserFields(); const userFields = DataProvider.getUserFields();
res.status(200).send(userFields); res.status(200).send(userFields);
}; };
// Create controller for POST request to '/ontime/userfields' // Create controller for POST request to '/ontime/userfields'
// Returns ACK message // Returns ACK message
export const postUserFields = async (req, res) => { export const postUserFields = async (req: Request, res: Response) => {
if (failEmptyObjects(req.body, res)) { if (failEmptyObjects(req.body, res)) {
return; return;
} }
@@ -201,13 +205,13 @@ export const postUserFields = async (req, res) => {
await DataProvider.setUserFields(newData); await DataProvider.setUserFields(newData);
res.status(200).send(newData); res.status(200).send(newData);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
// Create controller for POST request to '/ontime/settings' // Create controller for POST request to '/ontime/settings'
// Returns - // Returns -
export const getSettings = async (req, res) => { export const getSettings = async (_req: Request, res: Response) => {
const settings = DataProvider.getSettings(); const settings = DataProvider.getSettings();
res.status(200).send(settings); res.status(200).send(settings);
}; };
@@ -227,7 +231,7 @@ function extractPin(value: string | undefined | null, fallback: string | null):
// Create controller for POST request to '/ontime/settings' // Create controller for POST request to '/ontime/settings'
// Returns ACK message // Returns ACK message
export const postSettings = async (req, res) => { export const postSettings = async (req: Request, res: Response) => {
if (failEmptyObjects(req.body, res)) { if (failEmptyObjects(req.body, res)) {
return; return;
} }
@@ -264,7 +268,7 @@ export const postSettings = async (req, res) => {
await DataProvider.setSettings(newData); await DataProvider.setSettings(newData);
res.status(200).send(newData); res.status(200).send(newData);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
@@ -272,7 +276,7 @@ export const postSettings = async (req, res) => {
* @description Get view Settings * @description Get view Settings
* @method GET * @method GET
*/ */
export const getViewSettings = async (req, res) => { export const getViewSettings = async (_req: Request, res: Response) => {
const views = DataProvider.getViewSettings(); const views = DataProvider.getViewSettings();
res.status(200).send(views); res.status(200).send(views);
}; };
@@ -281,7 +285,7 @@ export const getViewSettings = async (req, res) => {
* @description Change view Settings * @description Change view Settings
* @method POST * @method POST
*/ */
export const postViewSettings = async (req, res) => { export const postViewSettings = async (req: Request, res: Response) => {
if (failEmptyObjects(req.body, res)) { if (failEmptyObjects(req.body, res)) {
return; return;
} }
@@ -299,20 +303,20 @@ export const postViewSettings = async (req, res) => {
await DataProvider.setViewSettings(newData); await DataProvider.setViewSettings(newData);
res.status(200).send(newData); res.status(200).send(newData);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
// Create controller for GET request to '/ontime/osc' // Create controller for GET request to '/ontime/osc'
// Returns - // Returns -
export const getOSC = async (req, res) => { export const getOSC = async (_req: Request, res: Response) => {
const osc = DataProvider.getOsc(); const osc = DataProvider.getOsc();
res.status(200).send(osc); res.status(200).send(osc);
}; };
// Create controller for POST request to '/ontime/osc' // Create controller for POST request to '/ontime/osc'
// Returns ACK message // Returns ACK message
export const postOSC = async (req, res) => { export const postOSC = async (req: Request, res: Response) => {
if (failEmptyObjects(req.body, res)) { if (failEmptyObjects(req.body, res)) {
return; return;
} }
@@ -333,11 +337,11 @@ export const postOSC = async (req, res) => {
res.send(oscSettings).status(200); res.send(oscSettings).status(200);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
export const postOscSubscriptions = async (req, res) => { export const postOscSubscriptions = async (req: Request, res: Response) => {
if (failEmptyObjects(req.body, res)) { if (failEmptyObjects(req.body, res)) {
return; return;
} }
@@ -354,18 +358,18 @@ export const postOscSubscriptions = async (req, res) => {
res.send(oscSettings).status(200); res.send(oscSettings).status(200);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
// Create controller for GET request to '/ontime/http' // Create controller for GET request to '/ontime/http'
export const getHTTP = async (_req, res: Response<HttpSettings>) => { export const getHTTP = async (_req: Request, res: Response<HttpSettings>) => {
const http = DataProvider.getHttp(); const http = DataProvider.getHttp();
res.status(200).send(http); res.status(200).send(http);
}; };
// Create controller for POST request to '/ontime/http' // Create controller for POST request to '/ontime/http'
export const postHTTP = async (req, res) => { export const postHTTP = async (req: Request, res: Response) => {
if (failEmptyObjects(req.body, res)) { if (failEmptyObjects(req.body, res)) {
return; return;
} }
@@ -386,11 +390,11 @@ export const postHTTP = async (req, res) => {
res.send(httpSettings).status(200); res.send(httpSettings).status(200);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
export async function patchPartialProjectFile(req, res) { export async function patchPartialProjectFile(req: Request, res: Response) {
if (failEmptyObjects(req.body, res)) { if (failEmptyObjects(req.body, res)) {
return; return;
} }
@@ -414,14 +418,14 @@ export async function patchPartialProjectFile(req, res) {
} }
res.status(200).send(); res.status(200).send();
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
} }
/** /**
* uploads, parses and applies the data from a given file * uploads, parses and applies the data from a given file
*/ */
export const dbUpload = async (req, res) => { export const dbUpload = async (req: Request, res: Response) => {
if (!req.file) { if (!req.file) {
res.status(400).send({ message: 'File not found' }); res.status(400).send({ message: 'File not found' });
return; return;
@@ -440,7 +444,7 @@ export const dbUpload = async (req, res) => {
* uploads and parses an excel file * uploads and parses an excel file
* @returns parsed result * @returns parsed result
*/ */
export async function previewExcel(req, res) { export async function previewExcel(req, res: Response) {
if (!req.file) { if (!req.file) {
res.status(400).send({ message: 'File not found' }); res.status(400).send({ message: 'File not found' });
return; return;
@@ -452,7 +456,7 @@ export async function previewExcel(req, res) {
const data = await parseFile(file, req, res, options); const data = await parseFile(file, req, res, options);
res.status(200).send(data); res.status(200).send(data);
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
} }
@@ -475,7 +479,7 @@ export const postNew: RequestHandler = async (req, res) => {
await deleteAllEvents(); await deleteAllEvents();
res.status(201).send(newData); res.status(201).send(newData);
} catch (error) { } catch (error) {
res.status(400).send({ message: error.toString() }); res.status(400).send({ message: String(error) });
} }
}; };
@@ -497,7 +501,7 @@ export const listProjects: RequestHandler = async (_, res: Response<ProjectFileL
lastLoadedProject: lastLoadedProjectName, lastLoadedProject: lastLoadedProjectName,
}); });
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -523,7 +527,7 @@ export const loadProject: RequestHandler = async (req, res) => {
message: `Loaded project ${filename}`, message: `Loaded project ${filename}`,
}); });
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -537,7 +541,7 @@ export const loadProject: RequestHandler = async (req, res) => {
* a 409 status if there are validation errors, * a 409 status if there are validation errors,
* or a 500 status with an error message in case of an exception. * or a 500 status with an error message in case of an exception.
*/ */
export const duplicateProjectFile: RequestHandler = async (req, res) => { export const duplicateProjectFile: RequestHandler = async (req: Request, res: Response) => {
try { try {
const { filename } = req.params; const { filename } = req.params;
const { newFilename } = req.body; const { newFilename } = req.body;
@@ -557,7 +561,7 @@ export const duplicateProjectFile: RequestHandler = async (req, res) => {
message: `Duplicated project ${filename} to ${newFilename}`, message: `Duplicated project ${filename} to ${newFilename}`,
}); });
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -571,7 +575,7 @@ export const duplicateProjectFile: RequestHandler = async (req, res) => {
* a 409 status if there are validation errors, * a 409 status if there are validation errors,
* or a 500 status with an error message in case of an exception. * or a 500 status with an error message in case of an exception.
*/ */
export const renameProjectFile: RequestHandler = async (req, res) => { export const renameProjectFile: RequestHandler = async (req: Request, res: Response) => {
try { try {
const { newFilename } = req.body; const { newFilename } = req.body;
const { filename } = req.params; const { filename } = req.params;
@@ -599,7 +603,7 @@ export const renameProjectFile: RequestHandler = async (req, res) => {
message: `Renamed project ${filename} to ${newFilename}`, message: `Renamed project ${filename} to ${newFilename}`,
}); });
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -612,7 +616,7 @@ export const renameProjectFile: RequestHandler = async (req, res) => {
* a 409 status if there are validation errors, * a 409 status if there are validation errors,
* or a 500 status with an error message in case of an exception. * or a 500 status with an error message in case of an exception.
*/ */
export const createProjectFile: RequestHandler = async (req, res) => { export const createProjectFile: RequestHandler = async (req: Request, res: Response) => {
try { try {
const { filename } = req.body; const { filename } = req.body;
@@ -624,14 +628,13 @@ export const createProjectFile: RequestHandler = async (req, res) => {
return res.status(409).send({ message: errors.join(', ') }); return res.status(409).send({ message: errors.join(', ') });
} }
console.log(`----------------> Creating directory createProjectFile: ${projectFilePath}`);
await writeFile(projectFilePath, JSON.stringify(dbModel)); await writeFile(projectFilePath, JSON.stringify(dbModel));
res.status(200).send({ res.status(200).send({
message: `Created project ${filename}`, message: `Created project ${filename}`,
}); });
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -645,7 +648,7 @@ export const createProjectFile: RequestHandler = async (req, res) => {
* a 409 status if there are validation errors, * a 409 status if there are validation errors,
* or a 500 status with an error message in case of an exception. * or a 500 status with an error message in case of an exception.
*/ */
export const deleteProjectFile: RequestHandler = async (req, res) => { export const deleteProjectFile: RequestHandler = async (req: Request, res: Response) => {
try { try {
const { filename } = req.params; const { filename } = req.params;
@@ -669,7 +672,7 @@ export const deleteProjectFile: RequestHandler = async (req, res) => {
message: `Deleted project ${filename}`, message: `Deleted project ${filename}`,
}); });
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -678,7 +681,7 @@ export const deleteProjectFile: RequestHandler = async (req, res) => {
* @description SETP-1 POST Client Secrect * @description SETP-1 POST Client Secrect
* @returns parsed result * @returns parsed result
*/ */
export async function uploadSheetClientFile(req, res) { export async function uploadSheetClientFile(req, res: Response) {
if (!req.file.path) { if (!req.file.path) {
res.status(400).send({ message: 'File not found' }); res.status(400).send({ message: 'File not found' });
return; return;
@@ -688,7 +691,7 @@ export async function uploadSheetClientFile(req, res) {
await sheet.saveClientSecrets(client); await sheet.saveClientSecrets(client);
res.status(200).send('OK'); res.status(200).send('OK');
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
fs.unlink(req.file.path, (err) => { fs.unlink(req.file.path, (err) => {
if (err) logger.error(LogOrigin.Server, err.message); if (err) logger.error(LogOrigin.Server, err.message);
@@ -698,7 +701,7 @@ export async function uploadSheetClientFile(req, res) {
/** /**
* @description STEP-1 GET Client Secrect status * @description STEP-1 GET Client Secrect status
*/ */
export const getClientSecrect = async (req, res) => { export const getClientSecrect = async (req: Request, res: Response) => {
try { try {
const clientSecrectExists = await sheet.testClientSecret(); const clientSecrectExists = await sheet.testClientSecret();
if (clientSecrectExists) { if (clientSecrectExists) {
@@ -707,31 +710,31 @@ export const getClientSecrect = async (req, res) => {
res.status(500).send({ message: 'The Client ID does not exist' }); res.status(500).send({ message: 'The Client ID does not exist' });
} }
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
/** /**
* @description STEP-2 GET sheet authentication url * @description STEP-2 GET sheet authentication url
*/ */
export async function getAuthenticationUrl(req, res) { export async function getAuthenticationUrl(_req: Request, res: Response) {
try { try {
const authUrl = await sheet.openAuthServer(); const authUrl = await sheet.openAuthServer();
res.status(200).send(authUrl); res.status(200).send(authUrl);
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
} }
/** /**
* @description STEP-2 GET sheet authentication status * @description STEP-2 GET sheet authentication status
*/ */
export const getAuthentication = async (req, res) => { export const getAuthentication = async (_req: Request, res: Response) => {
try { try {
await sheet.testAuthentication(); await sheet.testAuthentication();
res.status(200).send(); res.status(200).send();
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -739,7 +742,7 @@ export const getAuthentication = async (req, res) => {
* @description STEP-3 POST sheet id * @description STEP-3 POST sheet id
* @returns list of worksheets * @returns list of worksheets
*/ */
export const postId = async (req, res) => { export const postId = async (req: Request, res: Response) => {
try { try {
const { id } = req.body; const { id } = req.body;
if (id.lenght < 40) { if (id.lenght < 40) {
@@ -748,20 +751,20 @@ export const postId = async (req, res) => {
const state = await sheet.testSheetId(id); const state = await sheet.testSheetId(id);
res.status(200).send(state); res.status(200).send(state);
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
/** /**
* @description STEP-4 POST worksheet * @description STEP-4 POST worksheet
*/ */
export const postWorksheet = async (req, res) => { export const postWorksheet = async (req: Request, res: Response) => {
try { try {
const { worksheet, id } = req.body; const { worksheet, id } = req.body;
const state = await sheet.testWorksheet(worksheet, id); const state = await sheet.testWorksheet(worksheet, id);
res.status(200).send(state); res.status(200).send(state);
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
}; };
@@ -769,25 +772,25 @@ export const postWorksheet = async (req, res) => {
* @description STEP-5 POST download undown to sheet * @description STEP-5 POST download undown to sheet
* @returns parsed result * @returns parsed result
*/ */
export async function pullSheet(req, res) { export async function pullSheet(req: Request, res: Response) {
try { try {
const { id, options } = req.body; const { id, options } = req.body;
const data = await sheet.pull(id, options); const data = await sheet.pull(id, options);
res.status(200).send(data); res.status(200).send(data);
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
} }
/** /**
* @description STEP-5 POST upload rundown to sheet * @description STEP-5 POST upload rundown to sheet
*/ */
export async function pushSheet(req, res) { export async function pushSheet(req: Request, res: Response) {
try { try {
const { id, options } = req.body; const { id, options } = req.body;
await sheet.push(id, options); await sheet.push(id, options);
res.status(200).send(); res.status(200).send();
} catch (error) { } catch (error) {
res.status(500).send({ message: error.toString() }); res.status(500).send({ message: String(error) });
} }
} }
@@ -255,7 +255,7 @@ export const validateProjectCreate = [
* *
*/ */
export const validateProjectFiles = (projectFiles: { filename?: string; newFilename?: string }): Array<string> => { export const validateProjectFiles = (projectFiles: { filename?: string; newFilename?: string }): Array<string> => {
const errors = []; const errors: string[] = [];
if (projectFiles.filename) { if (projectFiles.filename) {
const projectFilePath = join(uploadsFolderPath, projectFiles.filename); const projectFilePath = join(uploadsFolderPath, projectFiles.filename);
+1 -1
View File
@@ -35,7 +35,7 @@ const populateDb = () => {
* @param adapterToUse * @param adapterToUse
* @return {Promise<number|*>} * @return {Promise<number|*>}
*/ */
const parseDb = async (fileToRead, adapterToUse) => { const parseDb = async (fileToRead: string, adapterToUse: Low<DatabaseModel>) => {
if (validateFile(fileToRead)) { if (validateFile(fileToRead)) {
await adapterToUse.read(); await adapterToUse.read();
} else { } else {
+1 -1
View File
@@ -81,7 +81,7 @@ export class TimerService {
const newState = runtimeState.getState(); const newState = runtimeState.getState();
// handle end action if there was a timer playing // handle end action if there was a timer playing
if (newState.timer.playback === Playback.Play) { if (newState.timer.playback === Playback.Play && newState.eventNow) {
if (newState.eventNow.endAction === EndAction.Stop) { if (newState.eventNow.endAction === EndAction.Stop) {
runtimeState.stop(); runtimeState.stop();
} else if (newState.eventNow.endAction === EndAction.LoadNext) { } else if (newState.eventNow.endAction === EndAction.LoadNext) {
@@ -860,7 +860,7 @@ describe('getRollTimers()', () => {
publicIndex: null, publicIndex: null,
nextIndex: 0, nextIndex: 0,
publicNextIndex: 4, publicNextIndex: 4,
timeToNext: dayInMs - now + eventlist[0].timeStart, timeToNext: dayInMs - now + eventlist[0].timeStart!,
nextEvent: eventlist[0], nextEvent: eventlist[0],
nextPublicEvent: eventlist[4], nextPublicEvent: eventlist[4],
currentEvent: null, currentEvent: null,
@@ -887,7 +887,7 @@ describe('getRollTimers()', () => {
publicIndex: null, publicIndex: null,
nextIndex: 0, nextIndex: 0,
publicNextIndex: 0, publicNextIndex: 0,
timeToNext: dayInMs - now + singleEventList[0].timeStart, timeToNext: dayInMs - now + singleEventList[0].timeStart!,
nextEvent: singleEventList[0], nextEvent: singleEventList[0],
nextPublicEvent: singleEventList[0], nextPublicEvent: singleEventList[0],
currentEvent: null, currentEvent: null,
@@ -1,10 +1,11 @@
import { MaybeNumber } from 'ontime-types';
import { millisToString, removeLeadingZero } from 'ontime-utils'; import { millisToString, removeLeadingZero } from 'ontime-utils';
// any value inside double curly braces {{val}} // any value inside double curly braces {{val}}
const placeholderRegex = /{{(.*?)}}/g; const placeholderRegex = /{{(.*?)}}/g;
function formatDisplayFromString(value: string, hideZero = false): string { function formatDisplayFromString(value: string, hideZero = false): string {
let valueInNumber = null; let valueInNumber: MaybeNumber = null;
if (value !== 'null') { if (value !== 'null') {
const parsedValue = Number(value); const parsedValue = Number(value);
@@ -48,7 +49,7 @@ export function parseTemplateNested(template: string, state: object, humanReadab
for (const match of matches) { for (const match of matches) {
const variableName = match[1]; const variableName = match[1];
const variableParts = variableName.split('.'); const variableParts = variableName.split('.');
let value = undefined; let value: string | undefined = undefined;
if (variableParts[0] === 'human') { if (variableParts[0] === 'human') {
const lookupKey = variableParts[1]; const lookupKey = variableParts[1];
@@ -4,7 +4,7 @@ import { throttle } from '../../utils/throttle.js';
import type { PublishFn } from '../../stores/EventStore.js'; import type { PublishFn } from '../../stores/EventStore.js';
let instance; let instance: MessageService | null = null;
class MessageService { class MessageService {
timer: TimerMessage; timer: TimerMessage;
@@ -56,7 +56,7 @@ class MessageService {
init(publish: PublishFn) { init(publish: PublishFn) {
this.publish = publish; this.publish = publish;
this.throttledSet = throttle((key, value) => this.publish(key, value), 100); this.throttledSet = throttle((key, value) => this.publish?.(key, value), 100);
} }
getState(): MessageState { getState(): MessageState {
@@ -104,7 +104,8 @@ export async function editEvent(patch: Partial<OntimeEvent> | Partial<OntimeBloc
} }
const scopedMutation = cache.mutateCache(cache.edit); const scopedMutation = cache.mutateCache(cache.edit);
const { newEvent } = await scopedMutation({ patch, eventId: patch.id }); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know patch has an id
const { newEvent } = await scopedMutation({ patch, eventId: patch.id! });
notifyChanges({ timer: [patch.id], external: true }); notifyChanges({ timer: [patch.id], external: true });
@@ -104,7 +104,7 @@ export function get(): Readonly<RundownCache> {
} }
type CommonParams = { persistedRundown: OntimeRundown }; type CommonParams = { persistedRundown: OntimeRundown };
type MutationParams<T> = T & Partial<CommonParams>; type MutationParams<T> = T & CommonParams;
type MutatingReturn = { type MutatingReturn = {
newRundown: OntimeRundown; newRundown: OntimeRundown;
newEvent?: OntimeRundownEntry; newEvent?: OntimeRundownEntry;
@@ -166,6 +166,9 @@ class RuntimeService {
*/ */
startById(eventId: string): boolean { startById(eventId: string): boolean {
const event = getEventWithId(eventId); const event = getEventWithId(eventId);
if (!event) {
return false;
}
const success = this.loadEvent(event); const success = this.loadEvent(event);
if (success) { if (success) {
this.start(); this.start();
@@ -180,6 +183,9 @@ class RuntimeService {
*/ */
startByIndex(eventIndex: number): boolean { startByIndex(eventIndex: number): boolean {
const event = getEventAtIndex(eventIndex); const event = getEventAtIndex(eventIndex);
if (!event) {
return false;
}
const success = this.loadEvent(event); const success = this.loadEvent(event);
if (success) { if (success) {
this.start(); this.start();
@@ -194,6 +200,9 @@ class RuntimeService {
*/ */
startByCue(cue: string): boolean { startByCue(cue: string): boolean {
const event = getEventWithCue(cue); const event = getEventWithCue(cue);
if (!event) {
return false;
}
const success = this.loadEvent(event); const success = this.loadEvent(event);
if (success) { if (success) {
this.start(); this.start();
@@ -208,6 +217,9 @@ class RuntimeService {
*/ */
loadById(eventId: string): boolean { loadById(eventId: string): boolean {
const event = getEventWithId(eventId); const event = getEventWithId(eventId);
if (!event) {
return false;
}
const success = this.loadEvent(event); const success = this.loadEvent(event);
return success; return success;
} }
@@ -219,6 +231,9 @@ class RuntimeService {
*/ */
loadByIndex(eventIndex: number): boolean { loadByIndex(eventIndex: number): boolean {
const event = getEventAtIndex(eventIndex); const event = getEventAtIndex(eventIndex);
if (!event) {
return false;
}
const success = this.loadEvent(event); const success = this.loadEvent(event);
return success; return success;
} }
@@ -230,6 +245,9 @@ class RuntimeService {
*/ */
loadByCue(cue: string): boolean { loadByCue(cue: string): boolean {
const event = getEventWithCue(cue); const event = getEventWithCue(cue);
if (!event) {
return false;
}
const success = this.loadEvent(event); const success = this.loadEvent(event);
return success; return success;
} }
+7 -1
View File
@@ -14,6 +14,11 @@ export const normaliseEndTime = (start: number, end: number) => (end < start ? e
*/ */
export function getExpectedFinish(state: RuntimeState): MaybeNumber { export function getExpectedFinish(state: RuntimeState): MaybeNumber {
const { startedAt, finishedAt, duration, addedTime } = state.timer; const { startedAt, finishedAt, duration, addedTime } = state.timer;
if (state.eventNow === null) {
return null;
}
const { timerType, timeEnd } = state.eventNow; const { timerType, timeEnd } = state.eventNow;
const { pausedAt } = state._timer; const { pausedAt } = state._timer;
const { clock } = state; const { clock } = state;
@@ -33,7 +38,8 @@ export function getExpectedFinish(state: RuntimeState): MaybeNumber {
} }
// handle events that finish the day after // handle events that finish the day after
const expectedFinish = startedAt + duration + addedTime + pausedTime; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- duration exists if ther eis a timer
const expectedFinish = startedAt + duration! + addedTime + pausedTime;
if (expectedFinish > dayInMs) { if (expectedFinish > dayInMs) {
return expectedFinish - dayInMs; return expectedFinish - dayInMs;
} }
+3 -3
View File
@@ -19,13 +19,13 @@ export function getAppDataPath(): string {
switch (process.platform) { switch (process.platform) {
case 'darwin': { case 'darwin': {
return path.join(process.env.HOME, 'Library', 'Application Support', 'Ontime'); return path.join(process.env.HOME!, 'Library', 'Application Support', 'Ontime');
} }
case 'win32': { case 'win32': {
return path.join(process.env.APPDATA, 'Ontime'); return path.join(process.env.APPDATA!, 'Ontime');
} }
case 'linux': { case 'linux': {
return path.join(process.env.HOME, '.Ontime'); return path.join(process.env.HOME!, '.Ontime');
} }
default: { default: {
throw new Error('Could not resolve public folder for platform'); throw new Error('Could not resolve public folder for platform');
@@ -77,7 +77,7 @@ describe('mutation on runtimeState', () => {
// 1. Load event // 1. Load event
load(mockEvent, [mockEvent]); load(mockEvent, [mockEvent]);
let newState = getState(); let newState = getState();
expect(newState.eventNow.id).toBe(mockEvent.id); expect(newState.eventNow?.id).toBe(mockEvent.id);
expect(newState.timer.playback).toBe(Playback.Armed); expect(newState.timer.playback).toBe(Playback.Armed);
expect(newState.clock).not.toBe(666); expect(newState.clock).not.toBe(666);
+1 -1
View File
@@ -8,7 +8,7 @@
*/ */
export function throttle<T extends any[], U>(cb: (...args: T) => U, delay: number) { export function throttle<T extends any[], U>(cb: (...args: T) => U, delay: number) {
let shouldWait = false; let shouldWait = false;
let waitingArgs; let waitingArgs: T | null = null;
const timeoutFunc = () => { const timeoutFunc = () => {
if (waitingArgs == null) { if (waitingArgs == null) {
shouldWait = false; shouldWait = false;
+5 -4
View File
@@ -1,4 +1,5 @@
import multer from 'multer'; import { Request } from 'express';
import multer, { FileFilterCallback } from 'multer';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
@@ -6,12 +7,12 @@ import { EXCEL_MIME, JSON_MIME } from './parser.js';
import { ensureDirectory } from './fileManagement.js'; import { ensureDirectory } from './fileManagement.js';
import { getAppDataPath } from '../setup.js'; import { getAppDataPath } from '../setup.js';
function generateNewFileName(filePath, callback) { function generateNewFileName(filePath: string, callback: (newName: string) => void) {
const baseName = path.basename(filePath, path.extname(filePath)); const baseName = path.basename(filePath, path.extname(filePath));
const extension = path.extname(filePath); const extension = path.extname(filePath);
let counter = 1; let counter = 1;
const checkExistence = (newPath) => { const checkExistence = (newPath: string) => {
fs.access(newPath, fs.constants.F_OK, (err) => { fs.access(newPath, fs.constants.F_OK, (err) => {
if (err) { if (err) {
// File with the new name does not exist, use this name // File with the new name does not exist, use this name
@@ -64,7 +65,7 @@ const storage = multer.diskStorage({
* @argument file - reference to file * @argument file - reference to file
* @return {boolean} - file allowed * @return {boolean} - file allowed
*/ */
const filterAllowed = (req, file, cb) => { const filterAllowed = (_req: Request, file: Express.Multer.File, cb: FileFilterCallback) => {
if (file.mimetype.includes(JSON_MIME) || file.mimetype.includes(EXCEL_MIME)) { if (file.mimetype.includes(JSON_MIME) || file.mimetype.includes(EXCEL_MIME)) {
cb(null, true); cb(null, true);
} else { } else {
+2 -2
View File
@@ -12,7 +12,7 @@
"experimentalDecorators": true, "experimentalDecorators": true,
}, },
"include": [ "include": [
"src/**/*" "src/**/*.ts",
"src/**/*.js",
], ],
"exclude": ["node_modules", "build"],
} }
+18
View File
@@ -304,9 +304,15 @@ importers:
specifier: ^8.13.0 specifier: ^8.13.0
version: 8.13.0 version: 8.13.0
devDependencies: devDependencies:
'@types/cors':
specifier: ^2.8.17
version: 2.8.17
'@types/express': '@types/express':
specifier: ^4.17.17 specifier: ^4.17.17
version: 4.17.17 version: 4.17.17
'@types/multer':
specifier: ^1.4.11
version: 1.4.11
'@types/node': '@types/node':
specifier: ^18.11.18 specifier: ^18.11.18
version: 18.11.18 version: 18.11.18
@@ -3161,6 +3167,12 @@ packages:
'@types/node': 18.19.3 '@types/node': 18.19.3
dev: true dev: true
/@types/cors@2.8.17:
resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==}
dependencies:
'@types/node': 18.19.3
dev: true
/@types/debug@4.1.12: /@types/debug@4.1.12:
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
dependencies: dependencies:
@@ -3252,6 +3264,12 @@ packages:
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
dev: true dev: true
/@types/multer@1.4.11:
resolution: {integrity: sha512-svK240gr6LVWvv3YGyhLlA+6LRRWA4mnGIU7RcNmgjBYFl6665wcXrRfxGp5tEPVHUNm5FMcmq7too9bxCwX/w==}
dependencies:
'@types/express': 4.17.17
dev: true
/@types/node-osc@6.0.2: /@types/node-osc@6.0.2:
resolution: {integrity: sha512-/TxCH+NlDoI3hFA6b2O91dpnPAqBDkLb2HEIv5hMVdKnCiWTdJJv2sVnQdX38sBgnals8TjCQEGii+OcMVf2fg==} resolution: {integrity: sha512-/TxCH+NlDoI3hFA6b2O91dpnPAqBDkLb2HEIv5hMVdKnCiWTdJJv2sVnQdX38sBgnals8TjCQEGii+OcMVf2fg==}
dependencies: dependencies: