From 98a4f058dd33c1be910ba001173a41796acc0e41 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 10:14:09 +0100 Subject: [PATCH 001/335] fix: add error logging across multiple components and services --- Common/Server/API/StatusPageAPI.ts | 1 + .../Middleware/NotificationMiddleware.ts | 2 ++ Common/Server/Middleware/UserAuthorization.ts | 1 + .../Server/Services/StatusPageDomainService.ts | 1 + .../Workflow/Components/JSON/JsonToText.ts | 2 ++ .../Workflow/Components/JSON/TextToJson.ts | 2 ++ Common/Server/Utils/CronTab.ts | 2 ++ Common/Server/Utils/JsonWebToken.ts | 2 ++ .../Criteria/CustomCodeMonitorCriteria.ts | 2 ++ Common/Server/Utils/Monitor/MonitorResource.ts | 1 + Common/Server/Utils/VM/VMAPI.ts | 3 +++ Common/UI/Components/Detail/Detail.tsx | 4 +++- Common/UI/Components/Forms/Validation.ts | 2 ++ Common/UI/Components/LogsViewer/LogItem.tsx | 2 ++ .../UI/Components/ProgressBar/ProgressBar.tsx | 2 ++ Common/UI/Utils/Cookie.ts | 2 ++ Common/UI/Utils/LocalStorage.ts | 2 ++ Common/UI/Utils/Logger.ts | 18 ++++++++++-------- Common/UI/Utils/SessionStorage.ts | 2 ++ Copilot/Index.ts | 1 + ...hOnCallSchedulesToAddCurrentUserOnRoster.ts | 2 +- Worker/DataMigrations/RefreshProjectUsers.ts | 2 +- 22 files changed, 47 insertions(+), 11 deletions(-) diff --git a/Common/Server/API/StatusPageAPI.ts b/Common/Server/API/StatusPageAPI.ts index 8382203f02..ddd311d1ee 100644 --- a/Common/Server/API/StatusPageAPI.ts +++ b/Common/Server/API/StatusPageAPI.ts @@ -228,6 +228,7 @@ export default class StatusPageAPI extends BaseAPI< try { statusPageId = new ObjectID(statusPageIdOrDomain); } catch (err) { + logger.error(err); return Response.sendErrorResponse( req, res, diff --git a/Common/Server/Middleware/NotificationMiddleware.ts b/Common/Server/Middleware/NotificationMiddleware.ts index c25f886e70..1e50c6b4a6 100644 --- a/Common/Server/Middleware/NotificationMiddleware.ts +++ b/Common/Server/Middleware/NotificationMiddleware.ts @@ -6,6 +6,7 @@ import { } from "../Utils/Express"; import JSONWebToken from "../Utils/JsonWebToken"; import Response from "../Utils/Response"; +import logger from "../Utils/Logger"; import { OnCallInputRequest } from "../../Types/Call/CallRequest"; import BadDataException from "../../Types/Exception/BadDataException"; import JSONFunctions from "../../Types/JSONFunctions"; @@ -61,6 +62,7 @@ export default class NotificationMiddleware { JSONWebToken.decodeJsonPayload(token), ); } catch (e) { + logger.error(e); return Response.sendErrorResponse( req, res, diff --git a/Common/Server/Middleware/UserAuthorization.ts b/Common/Server/Middleware/UserAuthorization.ts index 025d031e82..a459d96b75 100644 --- a/Common/Server/Middleware/UserAuthorization.ts +++ b/Common/Server/Middleware/UserAuthorization.ts @@ -173,6 +173,7 @@ export default class UserMiddleware { oneuptimeRequest.userAuthorization = JSONWebToken.decode(accessToken); } catch (err) { // if the token is invalid or expired, it'll throw this error. + logger.error(err); oneuptimeRequest.userType = UserType.Public; return next(); } diff --git a/Common/Server/Services/StatusPageDomainService.ts b/Common/Server/Services/StatusPageDomainService.ts index 9426637e41..1278d1da28 100644 --- a/Common/Server/Services/StatusPageDomainService.ts +++ b/Common/Server/Services/StatusPageDomainService.ts @@ -237,6 +237,7 @@ export class Service extends DatabaseService { return true; } catch (err) { + logger.error(err); return false; } } diff --git a/Common/Server/Types/Workflow/Components/JSON/JsonToText.ts b/Common/Server/Types/Workflow/Components/JSON/JsonToText.ts index c8a0700c1c..9c286c5247 100644 --- a/Common/Server/Types/Workflow/Components/JSON/JsonToText.ts +++ b/Common/Server/Types/Workflow/Components/JSON/JsonToText.ts @@ -2,6 +2,7 @@ import ComponentCode, { RunOptions, RunReturnType } from "../../ComponentCode"; import BadDataException from "../../../../../Types/Exception/BadDataException"; import { JSONObject } from "../../../../../Types/JSON"; import JSONFunctions from "../../../../../Types/JSONFunctions"; +import logger from "../../../../Utils/Logger"; import ComponentMetadata, { Port, } from "../../../../../Types/Workflow/Component"; @@ -74,6 +75,7 @@ export default class JsonToText extends ComponentCode { executePort: successPort, }); } catch (err) { + logger.error(err); options.log("JSON is not in the correct format."); return Promise.resolve({ returnValues: {}, diff --git a/Common/Server/Types/Workflow/Components/JSON/TextToJson.ts b/Common/Server/Types/Workflow/Components/JSON/TextToJson.ts index b1d5186c2a..beff3948b4 100644 --- a/Common/Server/Types/Workflow/Components/JSON/TextToJson.ts +++ b/Common/Server/Types/Workflow/Components/JSON/TextToJson.ts @@ -2,6 +2,7 @@ import ComponentCode, { RunOptions, RunReturnType } from "../../ComponentCode"; import BadDataException from "../../../../../Types/Exception/BadDataException"; import { JSONObject } from "../../../../../Types/JSON"; import JSONFunctions from "../../../../../Types/JSONFunctions"; +import logger from "../../../../Utils/Logger"; import ComponentMetadata, { Port, } from "../../../../../Types/Workflow/Component"; @@ -72,6 +73,7 @@ export default class TextToJSON extends ComponentCode { executePort: successPort, }); } catch (err) { + logger.error(err); options.log("text is not in the correct format."); return Promise.resolve({ returnValues: {}, diff --git a/Common/Server/Utils/CronTab.ts b/Common/Server/Utils/CronTab.ts index b10d868288..7f8c5fc83a 100644 --- a/Common/Server/Utils/CronTab.ts +++ b/Common/Server/Utils/CronTab.ts @@ -1,5 +1,6 @@ import BadDataException from "../../Types/Exception/BadDataException"; import CronParser, { CronExpression } from "cron-parser"; +import logger from "./Logger"; import CaptureSpan from "./Telemetry/CaptureSpan"; export default class CronTab { @@ -10,6 +11,7 @@ export default class CronTab { const nextExecutionTime: Date = interval.next().toDate(); return nextExecutionTime; } catch (error) { + logger.error(error); throw new BadDataException(`Invalid cron expression: ${crontab}`); } } diff --git a/Common/Server/Utils/JsonWebToken.ts b/Common/Server/Utils/JsonWebToken.ts index e09dd1998a..76db089fa4 100644 --- a/Common/Server/Utils/JsonWebToken.ts +++ b/Common/Server/Utils/JsonWebToken.ts @@ -10,6 +10,7 @@ import Timezone from "../../Types/Timezone"; import StatusPagePrivateUser from "../../Models/DatabaseModels/StatusPagePrivateUser"; import User from "../../Models/DatabaseModels/User"; import jwt from "jsonwebtoken"; +import logger from "./Logger"; import CaptureSpan from "./Telemetry/CaptureSpan"; class JSONWebToken { @@ -119,6 +120,7 @@ class JSONWebToken { isGlobalLogin: Boolean(decoded["isGlobalLogin"]), }; } catch (e) { + logger.error(e); throw new BadDataException("AccessToken is invalid or expired"); } } diff --git a/Common/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.ts b/Common/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.ts index c8611332a0..0aca8738ba 100644 --- a/Common/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.ts +++ b/Common/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.ts @@ -4,6 +4,7 @@ import { CriteriaFilter, } from "../../../../Types/Monitor/CriteriaFilter"; import CustomCodeMonitorResponse from "../../../../Types/Monitor/CustomCodeMonitor/CustomCodeMonitorResponse"; +import logger from "../../Logger"; import CaptureSpan from "../../Telemetry/CaptureSpan"; export default class CustomCodeMonitoringCriteria { @@ -78,6 +79,7 @@ export default class CustomCodeMonitoringCriteria { thresholdAsNumber = parseFloat(threshold.toString()); } } catch (err) { + logger.error(err); thresholdAsNumber = null; } diff --git a/Common/Server/Utils/Monitor/MonitorResource.ts b/Common/Server/Utils/Monitor/MonitorResource.ts index 3fba6e4a2e..4ebbca2a91 100644 --- a/Common/Server/Utils/Monitor/MonitorResource.ts +++ b/Common/Server/Utils/Monitor/MonitorResource.ts @@ -1244,6 +1244,7 @@ export default class MonitorResourceUtil { .responseBody as string) || "{}", ); } catch (err) { + logger.error(err); responseBody = (input.dataToProcess as ProbeMonitorResponse) .responseBody as JSONObject; } diff --git a/Common/Server/Utils/VM/VMAPI.ts b/Common/Server/Utils/VM/VMAPI.ts index ea8adb0bad..2fe40c2ace 100644 --- a/Common/Server/Utils/VM/VMAPI.ts +++ b/Common/Server/Utils/VM/VMAPI.ts @@ -8,6 +8,7 @@ import URL from "../../../Types/API/URL"; import ReturnResult from "../../../Types/IsolatedVM/ReturnResult"; import { JSONObject, JSONValue } from "../../../Types/JSON"; import API from "../../../Utils/API"; +import logger from "../Logger"; import CaptureSpan from "../Telemetry/CaptureSpan"; export default class VMUtil { @@ -57,6 +58,7 @@ export default class VMUtil { valueToReplaceInPlace = JSON.stringify(valueToReplaceInPlace); didStringify = true; } catch (err) { + logger.error(err); return valueToReplaceInPlace; } } @@ -104,6 +106,7 @@ export default class VMUtil { try { valueToReplaceInPlace = JSON.parse(valueToReplaceInPlace); } catch (err) { + logger.error(err); return valueToReplaceInPlace; } } diff --git a/Common/UI/Components/Detail/Detail.tsx b/Common/UI/Components/Detail/Detail.tsx index cd627e652b..41990b3933 100644 --- a/Common/UI/Components/Detail/Detail.tsx +++ b/Common/UI/Components/Detail/Detail.tsx @@ -306,7 +306,9 @@ const Detail: DetailFunction = ( "Cant format json for field: " + field.title + " with value: " + - data, + data + + " Error: " + + e, ); } } diff --git a/Common/UI/Components/Forms/Validation.ts b/Common/UI/Components/Forms/Validation.ts index a68a51e6c3..046b45b59f 100644 --- a/Common/UI/Components/Forms/Validation.ts +++ b/Common/UI/Components/Forms/Validation.ts @@ -14,6 +14,7 @@ import Exception from "../../../Types/Exception/Exception"; import GenericObject from "../../../Types/GenericObject"; import { JSONObject } from "../../../Types/JSON"; import Phone from "../../../Types/Phone"; +import { Logger } from "../../Utils/Logger"; import Port from "../../../Types/Port"; import Typeof from "../../../Types/Typeof"; @@ -83,6 +84,7 @@ export default class Validation { try { content = parseInt(content); } catch (e) { + Logger.error(e as string); return `${field.title || name} should be a number.`; } } diff --git a/Common/UI/Components/LogsViewer/LogItem.tsx b/Common/UI/Components/LogsViewer/LogItem.tsx index 096789d37f..a096fbb6f1 100644 --- a/Common/UI/Components/LogsViewer/LogItem.tsx +++ b/Common/UI/Components/LogsViewer/LogItem.tsx @@ -6,6 +6,7 @@ import Log from "../../../Models/AnalyticsModels/Log"; import LogSeverity from "../../../Types/Log/LogSeverity"; import TelemetryService from "../../../Models/DatabaseModels/TelemetryService"; import React, { FunctionComponent, ReactElement, useEffect } from "react"; +import { Logger } from "../../Utils/Logger"; export interface ComponentProps { log: Log; @@ -58,6 +59,7 @@ const LogItem: FunctionComponent = ( logBody = JSON.stringify(JSON.parse(logBody), null, 2); isBodyInJSON = true; } catch (e) { + Logger.error(e as Error); isBodyInJSON = false; } diff --git a/Common/UI/Components/ProgressBar/ProgressBar.tsx b/Common/UI/Components/ProgressBar/ProgressBar.tsx index 32b69dc09d..1f8f6341e8 100644 --- a/Common/UI/Components/ProgressBar/ProgressBar.tsx +++ b/Common/UI/Components/ProgressBar/ProgressBar.tsx @@ -4,6 +4,7 @@ import React, { useEffect, useState, } from "react"; +import { Logger } from "../../Utils/Logger"; export enum ProgressBarSize { Small = "small", @@ -29,6 +30,7 @@ const ProgressBar: FunctionComponent = ( try { percent = (props.count * 100) / props.totalCount; } catch (err) { + Logger.error(err as Error); // do nothing. } diff --git a/Common/UI/Utils/Cookie.ts b/Common/UI/Utils/Cookie.ts index 1388c2f5eb..c85dd73e2a 100644 --- a/Common/UI/Utils/Cookie.ts +++ b/Common/UI/Utils/Cookie.ts @@ -7,6 +7,7 @@ import JSONFunctions from "../../Types/JSONFunctions"; import Typeof from "../../Types/Typeof"; import UniversalCookies, { CookieSetOptions } from "universal-cookie"; import CookieName from "../../Types/CookieName"; +import { Logger } from "./Logger"; export default class Cookie { public static clearAllCookies(): void { @@ -64,6 +65,7 @@ export default class Cookie { } return value; } catch (err) { + Logger.error(err as string); return value; } } diff --git a/Common/UI/Utils/LocalStorage.ts b/Common/UI/Utils/LocalStorage.ts index 2320185bf0..eb831b97ee 100644 --- a/Common/UI/Utils/LocalStorage.ts +++ b/Common/UI/Utils/LocalStorage.ts @@ -4,6 +4,7 @@ import Email from "../../Types/Email"; import { JSONObject, JSONValue } from "../../Types/JSON"; import JSONFunctions from "../../Types/JSONFunctions"; import Typeof from "../../Types/Typeof"; +import { Logger } from "./Logger"; export default class LocalStorage { public static setItem(key: string, value: JSONValue | Email | URL): void { @@ -27,6 +28,7 @@ export default class LocalStorage { } return value; } catch (err) { + Logger.error(err as string); return value; } } diff --git a/Common/UI/Utils/Logger.ts b/Common/UI/Utils/Logger.ts index de64c79a2c..84b2bfb84c 100644 --- a/Common/UI/Utils/Logger.ts +++ b/Common/UI/Utils/Logger.ts @@ -1,21 +1,23 @@ +import GenericObject from "../../Types/GenericObject"; + export class Logger { - public static warn(text: string): void { + public static warn(text: string | GenericObject): void { //eslint-disable-next-line - console.warn(text); + console.warn(text); } - public static error(text: string): void { + public static error(text: string | GenericObject): void { //eslint-disable-next-line - console.error(text); + console.error(text); } - public static log(text: string): void { + public static log(text: string | GenericObject): void { //eslint-disable-next-line - console.log(text); + console.log(text); } - public static info(text: string): void { + public static info(text: string | GenericObject): void { //eslint-disable-next-line - this.log(text); + this.log(text); } } diff --git a/Common/UI/Utils/SessionStorage.ts b/Common/UI/Utils/SessionStorage.ts index 6f1e5fb59e..db08e82e25 100644 --- a/Common/UI/Utils/SessionStorage.ts +++ b/Common/UI/Utils/SessionStorage.ts @@ -4,6 +4,7 @@ import Email from "../../Types/Email"; import { JSONObject, JSONValue } from "../../Types/JSON"; import JSONFunctions from "../../Types/JSONFunctions"; import Typeof from "../../Types/Typeof"; +import { Logger } from "./Logger"; export default class SessionStorage { public static setItem(key: string, value: JSONValue | Email | URL): void { @@ -27,6 +28,7 @@ export default class SessionStorage { } return value; } catch (err) { + Logger.error(err as string); return value; } } diff --git a/Copilot/Index.ts b/Copilot/Index.ts index 51803a9579..62cbf19a9b 100644 --- a/Copilot/Index.ts +++ b/Copilot/Index.ts @@ -28,6 +28,7 @@ Init() // change back to main branch. await CodeRepositoryUtil.checkoutMainBranch(); } catch (e) { + logger.error(e); // do nothing. } diff --git a/Worker/DataMigrations/RefreshOnCallSchedulesToAddCurrentUserOnRoster.ts b/Worker/DataMigrations/RefreshOnCallSchedulesToAddCurrentUserOnRoster.ts index 955ca08581..af8840d1e7 100644 --- a/Worker/DataMigrations/RefreshOnCallSchedulesToAddCurrentUserOnRoster.ts +++ b/Worker/DataMigrations/RefreshOnCallSchedulesToAddCurrentUserOnRoster.ts @@ -34,7 +34,7 @@ export default class RefreshOnCallSchedulesToAddCurrentUserOnRoster extends Data logger.error( `Error refreshing current user and handoff time for schedule: ${schedule.id}`, ); - logger.error(err); + logger.error(err); } } } diff --git a/Worker/DataMigrations/RefreshProjectUsers.ts b/Worker/DataMigrations/RefreshProjectUsers.ts index fa999996fb..322bcc7245 100644 --- a/Worker/DataMigrations/RefreshProjectUsers.ts +++ b/Worker/DataMigrations/RefreshProjectUsers.ts @@ -34,7 +34,7 @@ export default class RefreshProjectUsers extends DataMigrationBase { logger.error( `Error refreshing project users for project: ${project.id}`, ); - logger.error(err); + logger.error(err); } } } From 9d3b2b5fc99c711ef96987707f6370b88e596757 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 10:26:42 +0100 Subject: [PATCH 002/335] fix: correct function call syntax in OrderedStatesList test and improve error handling in various classes --- .../Tests/UI/Components/OrderedStatesList.test.tsx | 2 +- Common/Types/API/EmptyResponse.ts | 3 ++- Common/Types/API/StatusCode.ts | 2 +- Common/Types/GenericFunction.ts | 2 +- Common/Types/IP/IP.ts | 2 +- Common/Types/Port.ts | 2 +- Common/UI/Components/Accordion/Accordion.tsx | 14 ++++++++------ 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Common/Tests/UI/Components/OrderedStatesList.test.tsx b/Common/Tests/UI/Components/OrderedStatesList.test.tsx index b12e7ba054..bfc2c16f85 100644 --- a/Common/Tests/UI/Components/OrderedStatesList.test.tsx +++ b/Common/Tests/UI/Components/OrderedStatesList.test.tsx @@ -26,7 +26,7 @@ describe("OrderedSateList", () => { it("should render all components", () => { render(); - expect(screen.getByText("item 1")).toBeInTheDocument; + expect(screen.getByText("item 1")).toBeInTheDocument(); }); it("renders Item components for each item in data prop", () => { const props: ComponentProps = { diff --git a/Common/Types/API/EmptyResponse.ts b/Common/Types/API/EmptyResponse.ts index 935ebd796d..5dcd09d2a7 100644 --- a/Common/Types/API/EmptyResponse.ts +++ b/Common/Types/API/EmptyResponse.ts @@ -1,3 +1,4 @@ import { JSONObject } from "../JSON"; -export default interface EmptyResponseData extends JSONObject {} +type EmptyResponseData = JSONObject; +export default EmptyResponseData; diff --git a/Common/Types/API/StatusCode.ts b/Common/Types/API/StatusCode.ts index 02f771f49e..ee9f2ab352 100644 --- a/Common/Types/API/StatusCode.ts +++ b/Common/Types/API/StatusCode.ts @@ -35,7 +35,7 @@ export default class StatusCode { } return false; - } catch (err) { + } catch { return false; } } diff --git a/Common/Types/GenericFunction.ts b/Common/Types/GenericFunction.ts index 48df879600..fcf5b6937c 100644 --- a/Common/Types/GenericFunction.ts +++ b/Common/Types/GenericFunction.ts @@ -1,4 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-restricted-types +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type type GenericFunction = Function; export default GenericFunction; diff --git a/Common/Types/IP/IP.ts b/Common/Types/IP/IP.ts index 21dd86917e..4d8afab7e8 100644 --- a/Common/Types/IP/IP.ts +++ b/Common/Types/IP/IP.ts @@ -69,7 +69,7 @@ export default class IP extends DatabaseProperty { if ((ipInt & mask) === (networkInt & mask)) { return true; } - } catch (error) { + } catch { continue; } } diff --git a/Common/Types/Port.ts b/Common/Types/Port.ts index 47ade04421..1235880b67 100644 --- a/Common/Types/Port.ts +++ b/Common/Types/Port.ts @@ -39,7 +39,7 @@ export default class Port extends DatabaseProperty { if (typeof port === Typeof.String) { try { port = Number.parseInt(port.toString().trim(), 10); - } catch (error) { + } catch { return false; } } diff --git a/Common/UI/Components/Accordion/Accordion.tsx b/Common/UI/Components/Accordion/Accordion.tsx index 0b22e29b01..62dc22f0e6 100644 --- a/Common/UI/Components/Accordion/Accordion.tsx +++ b/Common/UI/Components/Accordion/Accordion.tsx @@ -41,14 +41,16 @@ const Accordion: FunctionComponent = ( }, [props.title]); useEffect(() => { - props.onClick && props.onClick(); - - if (isOpen) { - props.onOpen && props.onOpen(); + if (props.onClick) { + props.onClick(); } - if (!isOpen) { - props.onClose && props.onClose(); + if (isOpen && props.onOpen) { + props.onOpen(); + } + + if (!isOpen && props.onClose) { + props.onClose(); } }, [isOpen]); From 73f248c367ac6ee664bb0091ae2375c6c7f3dd64 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 10:27:42 +0100 Subject: [PATCH 003/335] fix: improve error handling in CommonModel and update mock function to return a promise in BillingServiceHelper --- .../AnalyticsModels/AnalyticsBaseModel/CommonModel.ts | 4 ++-- .../TestingUtils/Services/BillingServiceHelper.ts | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Common/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts b/Common/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts index 26a3fa8fc7..2b89fea924 100644 --- a/Common/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts +++ b/Common/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts @@ -76,7 +76,7 @@ export default class CommonModel { if (column.type === TableColumnType.JSON && typeof value === "string") { try { value = JSONFunctions.parse(value); - } catch (e) { + } catch { value = {}; } } @@ -91,7 +91,7 @@ export default class CommonModel { if (!Array.isArray(value)) { throw new BadDataException("Not an array"); } - } catch (e) { + } catch { value = []; } } diff --git a/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts b/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts index 734124290d..eda997f9ac 100644 --- a/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +++ b/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts @@ -15,20 +15,18 @@ import SubscriptionPlan from "../../../../Types/Billing/SubscriptionPlan"; /// @dev consider modifyfing the EnvirontmentConfig to use functions instead of constants so that we can mock them -type MockIsBillingEnabledFunction = (value: boolean) => BillingService; +type MockIsBillingEnabledFunction = (value: boolean) => Promise; -const mockIsBillingEnabled: MockIsBillingEnabledFunction = ( +const mockIsBillingEnabled: MockIsBillingEnabledFunction = async ( value: boolean, -): BillingService => { +): Promise => { jest.resetModules(); jest.doMock("../../../../Server/BillingConfig", () => { return { IsBillingEnabled: value, }; }); - const { - BillingService, - } = require("../../../../Server/Services/BillingService"); + const { BillingService } = await import("../../../../Server/Services/BillingService"); return new BillingService(); }; From d6d5ecec643e58b51b73a224adcd4e2f5fc8905b Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 10:27:53 +0100 Subject: [PATCH 004/335] fix: correct syntax for checking disabled attribute in ConfirmModal test --- Common/Tests/UI/Components/ConfirmModal.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/Tests/UI/Components/ConfirmModal.test.tsx b/Common/Tests/UI/Components/ConfirmModal.test.tsx index f0b873ba2a..cebf1625c0 100644 --- a/Common/Tests/UI/Components/ConfirmModal.test.tsx +++ b/Common/Tests/UI/Components/ConfirmModal.test.tsx @@ -77,7 +77,7 @@ describe("ConfirmModal", () => { "modal-footer-submit-button", ); - expect(submitButton.getAttribute("disabled")).toBeTruthy; + expect(submitButton.getAttribute("disabled")).toBeTruthy(); }); it("should have a title content displayed in document when there is error", () => { From 2b801c3d08239a1b9cca90cb324b81500766764f Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 10:28:36 +0100 Subject: [PATCH 005/335] fix: update action start and end handlers to use explicit checks before calling --- Common/UI/Components/BulkUpdate/BulkUpdateForm.tsx | 8 ++++++-- Common/UI/Components/Button/Button.tsx | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Common/UI/Components/BulkUpdate/BulkUpdateForm.tsx b/Common/UI/Components/BulkUpdate/BulkUpdateForm.tsx index c5bc531f5c..deeeb1184f 100644 --- a/Common/UI/Components/BulkUpdate/BulkUpdateForm.tsx +++ b/Common/UI/Components/BulkUpdate/BulkUpdateForm.tsx @@ -225,7 +225,9 @@ const BulkUpdateForm: ( totalItems: props.selectedItems, }); setActionInProgress(true); - props.onActionStart && props.onActionStart(); + if (props.onActionStart) { + props.onActionStart(); + } }, onBulkActionEnd: () => { setActionInProgress(false); @@ -290,7 +292,9 @@ const BulkUpdateForm: ( submitButtonText="Close" onSubmit={() => { setShowProgressInfoModal(false); - props.onActionEnd && props.onActionEnd(); + if (props.onActionEnd) { + props.onActionEnd(); + } }} /> )} diff --git a/Common/UI/Components/Button/Button.tsx b/Common/UI/Components/Button/Button.tsx index 42a17e41ad..cf485a6df5 100644 --- a/Common/UI/Components/Button/Button.tsx +++ b/Common/UI/Components/Button/Button.tsx @@ -97,7 +97,9 @@ const Button: FunctionComponent = ({ switch (event.key) { case shortcutKey.toUpperCase(): case shortcutKey.toLowerCase(): - onClick && onClick(); + if (onClick) { + onClick(); + } return; default: return; From dd52a97dfa186d39701ba4cb11353ce504256a6a Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 13:08:28 +0100 Subject: [PATCH 006/335] fix: improve error handling by replacing catch blocks with empty catch statements across multiple components --- Common/Types/GenericFunction.ts | 2 +- .../CategoryCheckbox/CheckboxList.tsx | 8 ++++++-- .../UI/Components/CodeEditor/CodeEditor.tsx | 16 +++++++++++---- Common/UI/Components/Radio/Radio.tsx | 14 +++++++++---- Common/UI/Components/Tabs/Tabs.tsx | 4 ++-- Common/UI/Components/TextArea/TextArea.tsx | 4 +++- .../AnalyticsModelAPI/AnalyticsModelAPI.ts | 4 ++-- Common/UI/Utils/ModelAPI/ModelAPI.ts | 4 ++-- .../Components/Form/Monitor/MonitorStep.tsx | 2 +- Dashboard/src/Components/Header/Header.tsx | 2 +- Dashboard/src/Components/Header/Logo.tsx | 4 +++- .../src/Components/Monitor/MonitorMetrics.tsx | 4 ++-- Dashboard/src/Pages/Home/SideMenu.tsx | 4 ++-- Dashboard/src/Pages/Settings/Billing.tsx | 2 +- Dashboard/src/Pages/Settings/Invoices.tsx | 2 +- .../src/Pages/Settings/MonitorSecrets.tsx | 2 +- Dashboard/src/Pages/Settings/UsageHistory.tsx | 2 +- E2E/Tests/Accounts/Register.spec.ts | 4 ++-- FluentIngest/API/FluentIngest.ts | 2 +- MCP/Service/ModelAPI.ts | 4 ++-- .../Utils/Monitors/MonitorTypes/SslMonitor.ts | 2 +- Scripts/TerraformProvider/GenerateProvider.ts | 2 +- StatusPage/Serve.ts | 2 +- StatusPage/src/Components/Banner/Banner.tsx | 4 +++- .../src/Pages/Subscribe/SlackSubscribe.tsx | 2 +- .../AddTelemetryServiceColor.ts | 20 +++++++++---------- 26 files changed, 73 insertions(+), 49 deletions(-) diff --git a/Common/Types/GenericFunction.ts b/Common/Types/GenericFunction.ts index fcf5b6937c..dd154c4ca4 100644 --- a/Common/Types/GenericFunction.ts +++ b/Common/Types/GenericFunction.ts @@ -1,4 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/no-restricted-types type GenericFunction = Function; export default GenericFunction; diff --git a/Common/UI/Components/CategoryCheckbox/CheckboxList.tsx b/Common/UI/Components/CategoryCheckbox/CheckboxList.tsx index a37744ddd0..51314b09bb 100644 --- a/Common/UI/Components/CategoryCheckbox/CheckboxList.tsx +++ b/Common/UI/Components/CategoryCheckbox/CheckboxList.tsx @@ -57,7 +57,9 @@ const CheckBoxList: FunctionComponent = ( )} onChange={(changedValue: boolean) => { if (changedValue) { - props.onChecked && props.onChecked(option.value); + if (props.onChecked) { + props.onChecked(option.value); + } // add the option.value to the currentValues array const newValues: Array = [ @@ -72,7 +74,9 @@ const CheckBoxList: FunctionComponent = ( setCurrentValues(newValues); props.onChange(newValues); } else { - props.onUnchecked && props.onUnchecked(option.value); + if (props.onUnchecked) { + props.onUnchecked(option.value); + } // remove the option.value from the currentValues array diff --git a/Common/UI/Components/CodeEditor/CodeEditor.tsx b/Common/UI/Components/CodeEditor/CodeEditor.tsx index b6e4dd68e2..5cabaa6cda 100644 --- a/Common/UI/Components/CodeEditor/CodeEditor.tsx +++ b/Common/UI/Components/CodeEditor/CodeEditor.tsx @@ -101,8 +101,12 @@ const CodeEditor: FunctionComponent = (
{ - props.onClick && props.onClick(); - props.onFocus && props.onFocus(); + if (props.onClick) { + props.onClick(); + } + if (props.onFocus) { + props.onFocus(); + } }} > {helpText && ( @@ -122,8 +126,12 @@ const CodeEditor: FunctionComponent = ( } setValue(code); - props.onBlur && props.onBlur(); - props.onChange && props.onChange(code); + if (props.onBlur) { + props.onBlur(); + } + if (props.onChange) { + props.onChange(code); + } }} defaultValue={value || placeholder || ""} className={className} diff --git a/Common/UI/Components/Radio/Radio.tsx b/Common/UI/Components/Radio/Radio.tsx index d838634d0d..7f2b3593a2 100644 --- a/Common/UI/Components/Radio/Radio.tsx +++ b/Common/UI/Components/Radio/Radio.tsx @@ -7,7 +7,7 @@ import React, { useState, } from "react"; -export interface RadioOption extends DropdownOption {} +export type RadioOption = DropdownOption; export type RadioValue = DropdownValue; @@ -50,9 +50,15 @@ const Radio: FunctionComponent = ( checked={value === option.value} onClick={() => { setValue(option.value); - props.onChange && props.onChange(option.value); - props.onBlur && props.onBlur(); - props.onFocus && props.onFocus(); + if (props.onChange) { + props.onChange(option.value); + } + if (props.onBlur) { + props.onBlur(); + } + if (props.onFocus) { + props.onFocus(); + } }} name={groupName} type="radio" diff --git a/Common/UI/Components/Tabs/Tabs.tsx b/Common/UI/Components/Tabs/Tabs.tsx index 84d756443a..32382b4704 100644 --- a/Common/UI/Components/Tabs/Tabs.tsx +++ b/Common/UI/Components/Tabs/Tabs.tsx @@ -21,8 +21,8 @@ const Tabs: FunctionComponent = ( }, [props.tabs]); useEffect(() => { - if (currentTab) { - props.onTabChange && props.onTabChange(currentTab); + if (currentTab && props.onTabChange) { + props.onTabChange(currentTab); } }, [currentTab]); diff --git a/Common/UI/Components/TextArea/TextArea.tsx b/Common/UI/Components/TextArea/TextArea.tsx index da72aa4ab5..4f76cd37d6 100644 --- a/Common/UI/Components/TextArea/TextArea.tsx +++ b/Common/UI/Components/TextArea/TextArea.tsx @@ -50,7 +50,9 @@ const TextArea: FunctionComponent = ( const handleChange: HandleChangeFunction = (content: string): void => { setText(content); - props.onChange && props.onChange(content); + if (props.onChange) { + props.onChange(content); + } }; return ( diff --git a/Common/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts b/Common/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts index fc602e1a73..1b360f73e8 100644 --- a/Common/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +++ b/Common/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts @@ -24,8 +24,8 @@ import AggregateBy from "../../../Types/BaseDatabase/AggregateBy"; import AggregatedResult from "../../../Types/BaseDatabase/AggregatedResult"; import Query from "../../../Types/BaseDatabase/Query"; -export interface ListResult - extends BaseListResult {} +export type ListResult = + BaseListResult; export default class ModelAPI { public static async create< diff --git a/Common/UI/Utils/ModelAPI/ModelAPI.ts b/Common/UI/Utils/ModelAPI/ModelAPI.ts index 9483bc4651..2295626388 100644 --- a/Common/UI/Utils/ModelAPI/ModelAPI.ts +++ b/Common/UI/Utils/ModelAPI/ModelAPI.ts @@ -28,8 +28,8 @@ export class ModelAPIHttpResponse< public miscData?: JSONObject | undefined; } -export interface ListResult - extends BaseListResult {} +export type ListResult = + BaseListResult; export interface RequestOptions extends BaseRequestOptions { isMultiTenantRequest?: boolean | undefined; diff --git a/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx b/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx index 69a0777cb7..b1cefb5401 100644 --- a/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx +++ b/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx @@ -555,7 +555,7 @@ return { ...errors, requestBody: "", }); - } catch (err) { + } catch { setErrors({ ...errors, requestBody: "Invalid JSON", diff --git a/Dashboard/src/Components/Header/Header.tsx b/Dashboard/src/Components/Header/Header.tsx index b284c5a2da..44e044603a 100644 --- a/Dashboard/src/Components/Header/Header.tsx +++ b/Dashboard/src/Components/Header/Header.tsx @@ -318,7 +318,7 @@ const DashboardHeader: FunctionComponent = ( setCurrentOnCallPolicies(currentOnCallPolicies); } - } catch (err) { + } catch { setOnCallDutyPolicyFetchError( "Something isnt right, we are unable to fetch on-call policies that you are on duty for. Reload the page to try again.", ); diff --git a/Dashboard/src/Components/Header/Logo.tsx b/Dashboard/src/Components/Header/Logo.tsx index 1254999f1e..0519d525e2 100644 --- a/Dashboard/src/Components/Header/Logo.tsx +++ b/Dashboard/src/Components/Header/Logo.tsx @@ -17,7 +17,9 @@ const Logo: FunctionComponent = ( { - props.onClick && props.onClick(); + if (props.onClick) { + props.onClick(); + } }} imageUrl={Route.fromString(`${OneUptimeLogo}`)} alt={"OneUptime"} diff --git a/Dashboard/src/Components/Monitor/MonitorMetrics.tsx b/Dashboard/src/Components/Monitor/MonitorMetrics.tsx index 8128116223..8bac884c62 100644 --- a/Dashboard/src/Components/Monitor/MonitorMetrics.tsx +++ b/Dashboard/src/Components/Monitor/MonitorMetrics.tsx @@ -169,7 +169,7 @@ const MonitorMetricsElement: FunctionComponent = ( if (typeof attributes === "string") { try { attributes = JSONFunctions.parseJSONObject(attributes); - } catch (err) { + } catch { return { title: MonitorMetricTypeUtil.getTitleByMonitorMetricType( @@ -231,7 +231,7 @@ const MonitorMetricsElement: FunctionComponent = ( if (typeof attributes === "string") { try { attributes = JSONFunctions.parseJSONObject(attributes); - } catch (err) { + } catch { return { title: MonitorMetricTypeUtil.getTitleByMonitorMetricType( diff --git a/Dashboard/src/Pages/Home/SideMenu.tsx b/Dashboard/src/Pages/Home/SideMenu.tsx index 06f9a62832..353914e913 100644 --- a/Dashboard/src/Pages/Home/SideMenu.tsx +++ b/Dashboard/src/Pages/Home/SideMenu.tsx @@ -48,7 +48,7 @@ const DashboardSideMenu: FunctionComponent = ( ); setUnresolvedIncidentStates(unresolvedIncidentStates); } - } catch (err) { + } catch { // maybe show an error message } }; @@ -60,7 +60,7 @@ const DashboardSideMenu: FunctionComponent = ( await AlertStateUtil.getUnresolvedAlertStates(props.project?.id); setUnresolvedAlertStates(unresolvedAlertStates); } - } catch (err) { + } catch { // maybe show an error message } }; diff --git a/Dashboard/src/Pages/Settings/Billing.tsx b/Dashboard/src/Pages/Settings/Billing.tsx index 2b3206f4a0..fb6a23d55b 100644 --- a/Dashboard/src/Pages/Settings/Billing.tsx +++ b/Dashboard/src/Pages/Settings/Billing.tsx @@ -49,7 +49,7 @@ import React, { } from "react"; import useAsyncEffect from "use-async-effect"; -export interface ComponentProps extends PageComponentProps {} +export type ComponentProps = PageComponentProps; const Settings: FunctionComponent = ( _props: ComponentProps, diff --git a/Dashboard/src/Pages/Settings/Invoices.tsx b/Dashboard/src/Pages/Settings/Invoices.tsx index 4398b50512..f29f978c28 100644 --- a/Dashboard/src/Pages/Settings/Invoices.tsx +++ b/Dashboard/src/Pages/Settings/Invoices.tsx @@ -39,7 +39,7 @@ import BillingPaymentMethod from "Common/Models/DatabaseModels/BillingPaymentMet import { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax"; import ListResult from "Common/Types/BaseDatabase/ListResult"; -export interface ComponentProps extends PageComponentProps {} +export type ComponentProps = PageComponentProps; const Settings: FunctionComponent = ( _props: ComponentProps, diff --git a/Dashboard/src/Pages/Settings/MonitorSecrets.tsx b/Dashboard/src/Pages/Settings/MonitorSecrets.tsx index 6ce8032085..3cdbb62d28 100644 --- a/Dashboard/src/Pages/Settings/MonitorSecrets.tsx +++ b/Dashboard/src/Pages/Settings/MonitorSecrets.tsx @@ -212,7 +212,7 @@ const MonitorSecrets: FunctionComponent< }); setCurrentlyEditingItem(null); - } catch (err) { + } catch { // do nothing } diff --git a/Dashboard/src/Pages/Settings/UsageHistory.tsx b/Dashboard/src/Pages/Settings/UsageHistory.tsx index bf7c233f62..13253dc80f 100644 --- a/Dashboard/src/Pages/Settings/UsageHistory.tsx +++ b/Dashboard/src/Pages/Settings/UsageHistory.tsx @@ -13,7 +13,7 @@ import TelemetryService from "Common/Models/DatabaseModels/TelemetryService"; import TelemetryUsageBilling from "Common/Models/DatabaseModels/TelemetryUsageBilling"; import React, { Fragment, FunctionComponent, ReactElement } from "react"; -export interface ComponentProps extends PageComponentProps {} +export type ComponentProps = PageComponentProps; const Settings: FunctionComponent = ( _props: ComponentProps, diff --git a/E2E/Tests/Accounts/Register.spec.ts b/E2E/Tests/Accounts/Register.spec.ts index 9415024fb1..6f912f656f 100644 --- a/E2E/Tests/Accounts/Register.spec.ts +++ b/E2E/Tests/Accounts/Register.spec.ts @@ -22,7 +22,7 @@ test.describe("Account Registration", () => { try { // reload page if it fails to load dashboardPageResult = await page.reload(); - } catch (e) { + } catch { // reload page if it fails to load dashboardPageResult = await page.goto( URL.fromString(BASE_URL.toString()).addRoute("/dashboard").toString(), @@ -40,7 +40,7 @@ test.describe("Account Registration", () => { try { // reload page if it fails to load pageResult = await page.reload(); - } catch (e) { + } catch { // reload page if it fails to load pageResult = await page.goto( URL.fromString(BASE_URL.toString()) diff --git a/FluentIngest/API/FluentIngest.ts b/FluentIngest/API/FluentIngest.ts index 82c61316a2..08d490c832 100644 --- a/FluentIngest/API/FluentIngest.ts +++ b/FluentIngest/API/FluentIngest.ts @@ -99,7 +99,7 @@ router.post( // check if its parseable to json try { logItem = JSON.parse(logItem); - } catch (err) { + } catch { // do nothing } } diff --git a/MCP/Service/ModelAPI.ts b/MCP/Service/ModelAPI.ts index f3e6ccce38..f80398a098 100644 --- a/MCP/Service/ModelAPI.ts +++ b/MCP/Service/ModelAPI.ts @@ -23,8 +23,8 @@ export class ModelAPIHttpResponse< public miscData?: JSONObject | undefined; } -export interface ListResult - extends BaseListResult {} +export type ListResult = + BaseListResult; export default interface RequestOptions { requestHeaders?: Dictionary | undefined; diff --git a/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts b/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts index 927c7cec4e..db708f2b53 100644 --- a/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts +++ b/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts @@ -130,7 +130,7 @@ export default class SSLMonitor { port, rejectUnauthorized: true, }); - } catch (err) { + } catch { try { certificate = await this.getCertificate({ host, diff --git a/Scripts/TerraformProvider/GenerateProvider.ts b/Scripts/TerraformProvider/GenerateProvider.ts index 9c670824dd..1438bf4bf8 100644 --- a/Scripts/TerraformProvider/GenerateProvider.ts +++ b/Scripts/TerraformProvider/GenerateProvider.ts @@ -107,7 +107,7 @@ settings: try { execSync(generateCommand, { stdio: "inherit" }); Logger.info("✅ Terraform provider generated successfully"); - } catch (error: any) { + } catch { Logger.error("❌ Provider generation failed with tfplugingen-openapi"); Logger.info( "🔄 Trying alternative approach with direct Go generation...", diff --git a/StatusPage/Serve.ts b/StatusPage/Serve.ts index 364e289b44..d3a0bde4fc 100644 --- a/StatusPage/Serve.ts +++ b/StatusPage/Serve.ts @@ -99,7 +99,7 @@ const init: PromiseVoidFunction = async (): Promise => { "Status Page lets you see real-time information about the status of our services.", faviconUrl: `/status-page-api/favicon/${statusPageIdOrDomain}`, }; - } catch (err) { + } catch { return { title: "Status Page", description: diff --git a/StatusPage/src/Components/Banner/Banner.tsx b/StatusPage/src/Components/Banner/Banner.tsx index 845e741cfe..b289af160e 100644 --- a/StatusPage/src/Components/Banner/Banner.tsx +++ b/StatusPage/src/Components/Banner/Banner.tsx @@ -18,7 +18,9 @@ const Banner: FunctionComponent = (
{ - props.onClick && props.onClick(); + if (props.onClick) { + props.onClick(); + } }} className="rounded-xl w-full mt-5 mb-5" file={props.file} diff --git a/StatusPage/src/Pages/Subscribe/SlackSubscribe.tsx b/StatusPage/src/Pages/Subscribe/SlackSubscribe.tsx index c8728d474e..311e74e611 100644 --- a/StatusPage/src/Pages/Subscribe/SlackSubscribe.tsx +++ b/StatusPage/src/Pages/Subscribe/SlackSubscribe.tsx @@ -33,7 +33,7 @@ import { GetReactElementFunction } from "Common/UI/Types/FunctionTypes"; import SubscriberUtil from "Common/UI/Utils/StatusPage"; import FormValues from "Common/UI/Components/Forms/Types/FormValues"; -export interface ComponentProps extends SubscribePageProps {} +export type ComponentProps = SubscribePageProps; const SubscribePage: FunctionComponent = ( props: ComponentProps, diff --git a/Worker/DataMigrations/AddTelemetryServiceColor.ts b/Worker/DataMigrations/AddTelemetryServiceColor.ts index 10e80b72ba..e304e68604 100644 --- a/Worker/DataMigrations/AddTelemetryServiceColor.ts +++ b/Worker/DataMigrations/AddTelemetryServiceColor.ts @@ -29,16 +29,16 @@ export default class AddTelemetryServiceColor extends DataMigrationBase { for (const service of services) { if (!service.serviceColor) { - (service.serviceColor = ArrayUtil.selectItemByRandom(BrightColors)), - await TelemetryServiceService.updateOneById({ - id: service.id!, - data: { - serviceColor: service.serviceColor, - }, - props: { - isRoot: true, - }, - }); + service.serviceColor = ArrayUtil.selectItemByRandom(BrightColors); + await TelemetryServiceService.updateOneById({ + id: service.id!, + data: { + serviceColor: service.serviceColor, + }, + props: { + isRoot: true, + }, + }); } } } From d200ee3d6f672de8cb46202ac979338805d4f279 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 13:11:32 +0100 Subject: [PATCH 007/335] fix: format import statement for BillingService in mockIsBillingEnabled function --- .../Server/TestingUtils/Services/BillingServiceHelper.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts b/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts index eda997f9ac..f372ee60da 100644 --- a/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +++ b/Common/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts @@ -26,7 +26,9 @@ const mockIsBillingEnabled: MockIsBillingEnabledFunction = async ( IsBillingEnabled: value, }; }); - const { BillingService } = await import("../../../../Server/Services/BillingService"); + const { BillingService } = await import( + "../../../../Server/Services/BillingService" + ); return new BillingService(); }; From be6627cd2eed25b58b544dedb17ebee5e61b02c4 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 13:18:05 +0100 Subject: [PATCH 008/335] fix: refactor onClick handler in ColorInput to use explicit check for props.onClick --- Common/UI/Components/ColorViewer/ColorViewer.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/UI/Components/ColorViewer/ColorViewer.tsx b/Common/UI/Components/ColorViewer/ColorViewer.tsx index 3e306a6f16..4d988cbaf3 100644 --- a/Common/UI/Components/ColorViewer/ColorViewer.tsx +++ b/Common/UI/Components/ColorViewer/ColorViewer.tsx @@ -17,7 +17,9 @@ const ColorInput: FunctionComponent = (
{ - props.onClick && props.onClick(); + if (props.onClick) { + props.onClick(); + } }} data-testid={props.dataTestId} > From 8a3afb8fb093d97df9261882c146445e52dc6cb5 Mon Sep 17 00:00:00 2001 From: Simon Larsen Date: Wed, 11 Jun 2025 13:30:57 +0100 Subject: [PATCH 009/335] fix: simplify event handler checks using optional chaining for onClick and onChange props across multiple components --- .../UI/Components/ColorViewer/ColorViewer.tsx | 4 +- Common/UI/Components/Date/StartAndEndDate.tsx | 84 ++++++++----------- Common/UI/Components/Dropdown/Dropdown.tsx | 25 +++--- .../DuplicateModel/DuplicateModel.tsx | 2 +- .../Events/RecurringArrayFieldElement.tsx | 4 +- .../UI/Components/FilePicker/FilePicker.tsx | 10 +-- Common/UI/Components/Filters/FilterViewer.tsx | 6 +- .../Components/FormModal/BasicFormModal.tsx | 2 +- Common/UI/Components/Forms/BasicForm.tsx | 2 +- .../UI/Components/Forms/Fields/FormField.tsx | 6 +- Common/UI/Components/Forms/ModelForm.tsx | 4 +- .../FullPageModal/FullPageModal.tsx | 2 +- .../Header/HeaderIconDropdownButton.tsx | 4 +- .../UI/Components/HeaderAlert/HeaderAlert.tsx | 2 +- Common/UI/Components/Image/Image.tsx | 2 +- Common/UI/Components/Input/Input.tsx | 2 +- Common/UI/Components/List/List.tsx | 4 +- Common/UI/Components/Modal/ModalFooter.tsx | 2 +- .../UI/Components/ModelDelete/ModelDelete.tsx | 2 +- .../UI/Components/ModelDetail/ModelDetail.tsx | 6 +- Common/UI/Components/ModelList/ModelList.tsx | 4 +- .../Components/ModelList/StaticModelList.tsx | 4 +- .../Components/ModelTable/BaseModelTable.tsx | 4 +- Common/UI/Components/ModelTable/TableView.tsx | 6 +- Common/UI/Components/ObjectID/IDGenerator.tsx | 2 +- Common/UI/Components/Table/Table.tsx | 8 +- .../Form/Monitor/CriteriaFilters.tsx | 6 +- .../Form/Monitor/MonitorCriteriaAlertForm.tsx | 2 +- .../Monitor/MonitorCriteriaIncidentForm.tsx | 2 +- .../Components/Form/Monitor/MonitorStep.tsx | 8 +- .../Components/Metrics/MetricQueryConfig.tsx | 2 +- 31 files changed, 104 insertions(+), 119 deletions(-) diff --git a/Common/UI/Components/ColorViewer/ColorViewer.tsx b/Common/UI/Components/ColorViewer/ColorViewer.tsx index 4d988cbaf3..b22cbf387e 100644 --- a/Common/UI/Components/ColorViewer/ColorViewer.tsx +++ b/Common/UI/Components/ColorViewer/ColorViewer.tsx @@ -17,9 +17,7 @@ const ColorInput: FunctionComponent = (
{ - if (props.onClick) { - props.onClick(); - } + props.onClick?.(); }} data-testid={props.dataTestId} > diff --git a/Common/UI/Components/Date/StartAndEndDate.tsx b/Common/UI/Components/Date/StartAndEndDate.tsx index 02466bb109..4e4e7b07a0 100644 --- a/Common/UI/Components/Date/StartAndEndDate.tsx +++ b/Common/UI/Components/Date/StartAndEndDate.tsx @@ -134,13 +134,12 @@ const StartAndEndDate: DateFilterFunction = ( error={startDateError} onChange={(changedValue: string | Date) => { if (!changedValue) { - props.onValueChanged && - props.onValueChanged( - new InBetween( - OneUptimeDate.getCurrentDate(), - endDateTime || OneUptimeDate.getCurrentDate(), - ), - ); + props.onValueChanged?.( + new InBetween( + OneUptimeDate.getCurrentDate(), + endDateTime || OneUptimeDate.getCurrentDate(), + ), + ); } if ( @@ -148,13 +147,12 @@ const StartAndEndDate: DateFilterFunction = ( (props.type === StartAndEndDateType.Date || props.type === StartAndEndDateType.DateTime) ) { - props.onValueChanged && - props.onValueChanged( - new InBetween( - OneUptimeDate.fromString(changedValue as string), - endDateTime || OneUptimeDate.getCurrentDate(), - ), - ); + props.onValueChanged?.( + new InBetween( + OneUptimeDate.fromString(changedValue as string), + endDateTime || OneUptimeDate.getCurrentDate(), + ), + ); } }} value={startDateTime || ""} @@ -170,13 +168,12 @@ const StartAndEndDate: DateFilterFunction = ( error={endDateError} onChange={(changedValue: string | Date) => { if (!changedValue) { - props.onValueChanged && - props.onValueChanged( - new InBetween( - startDateTime || OneUptimeDate.getCurrentDate(), - OneUptimeDate.getCurrentDate(), - ), - ); + props.onValueChanged?.( + new InBetween( + startDateTime || OneUptimeDate.getCurrentDate(), + OneUptimeDate.getCurrentDate(), + ), + ); } if ( @@ -184,13 +181,12 @@ const StartAndEndDate: DateFilterFunction = ( (props.type === StartAndEndDateType.Date || props.type === StartAndEndDateType.DateTime) ) { - props.onValueChanged && - props.onValueChanged( - new InBetween( - startDateTime || OneUptimeDate.getCurrentDate(), - OneUptimeDate.fromString(changedValue as string), - ), - ); + props.onValueChanged?.( + new InBetween( + startDateTime || OneUptimeDate.getCurrentDate(), + OneUptimeDate.fromString(changedValue as string), + ), + ); } }} value={endDateTime || ""} @@ -217,10 +213,9 @@ const StartAndEndDate: DateFilterFunction = ( -1, ); - props.onValueChanged && - props.onValueChanged( - new InBetween(startDate, endDate), - ); + props.onValueChanged?.( + new InBetween(startDate, endDate), + ); }} title="1 hour" /> @@ -240,10 +235,9 @@ const StartAndEndDate: DateFilterFunction = ( -3, ); - props.onValueChanged && - props.onValueChanged( - new InBetween(startDate, endDate), - ); + props.onValueChanged?.( + new InBetween(startDate, endDate), + ); }} title="3 hours" /> @@ -262,8 +256,7 @@ const StartAndEndDate: DateFilterFunction = ( -1, ); - props.onValueChanged && - props.onValueChanged(new InBetween(startDate, endDate)); + props.onValueChanged?.(new InBetween(startDate, endDate)); }} title="1 day" /> @@ -281,8 +274,7 @@ const StartAndEndDate: DateFilterFunction = ( -7, ); - props.onValueChanged && - props.onValueChanged(new InBetween(startDate, endDate)); + props.onValueChanged?.(new InBetween(startDate, endDate)); }} title="1 week" /> @@ -300,8 +292,7 @@ const StartAndEndDate: DateFilterFunction = ( -14, ); - props.onValueChanged && - props.onValueChanged(new InBetween(startDate, endDate)); + props.onValueChanged?.(new InBetween(startDate, endDate)); }} title="2 weeks" /> @@ -319,8 +310,7 @@ const StartAndEndDate: DateFilterFunction = ( -21, ); - props.onValueChanged && - props.onValueChanged(new InBetween(startDate, endDate)); + props.onValueChanged?.(new InBetween(startDate, endDate)); }} title="3 weeks" /> @@ -338,8 +328,7 @@ const StartAndEndDate: DateFilterFunction = ( -1, ); - props.onValueChanged && - props.onValueChanged(new InBetween(startDate, endDate)); + props.onValueChanged?.(new InBetween(startDate, endDate)); }} title="1 month" /> @@ -357,8 +346,7 @@ const StartAndEndDate: DateFilterFunction = ( -3, ); - props.onValueChanged && - props.onValueChanged(new InBetween(startDate, endDate)); + props.onValueChanged?.(new InBetween(startDate, endDate)); }} title="3 months" /> diff --git a/Common/UI/Components/Dropdown/Dropdown.tsx b/Common/UI/Components/Dropdown/Dropdown.tsx index 3877072a01..b68f4a0290 100644 --- a/Common/UI/Components/Dropdown/Dropdown.tsx +++ b/Common/UI/Components/Dropdown/Dropdown.tsx @@ -133,20 +133,20 @@ const Dropdown: FunctionComponent = ( "relative mt-2 mb-1 rounded-md w-full overflow-visible" }`} onClick={() => { - props.onClick && props.onClick(); - props.onFocus && props.onFocus(); + props.onClick?.(); + props.onFocus?.(); }} > " as GenericObject, - query: "" as GenericObject, - props: "" as GenericObject, - sort: "" as GenericObject, + select: { columns: ["col1", "col2"] } as GenericObject, + query: { field: "value" } as GenericObject, + props: { prop: "test" } as GenericObject, + sort: { field: "asc" } as GenericObject, limit: 123, skip: 234, }); expect(service.statementGenerator.toSelectStatement).toBeCalledWith( - "); @@ -283,4 +284,25 @@ describe("Input", () => { expect(getByRole("textbox")).toHaveFocus(); }); + + test("enables spellcheck by default", () => { + const { getByRole } = render(); + const input: HTMLElement = getByRole("textbox"); + + expect(input).toHaveAttribute("spellcheck", "true"); + }); + + test("disables spellcheck when disableSpellCheck is true", () => { + const { getByRole } = render(); + const input: HTMLElement = getByRole("textbox"); + + expect(input).toHaveAttribute("spellcheck", "false"); + }); + + test("enables spellcheck when disableSpellCheck is false", () => { + const { getByRole } = render(); + const input: HTMLElement = getByRole("textbox"); + + expect(input).toHaveAttribute("spellcheck", "true"); + }); }); diff --git a/Common/Tests/UI/Components/TextArea.test.tsx b/Common/Tests/UI/Components/TextArea.test.tsx index d44e7421b6..98142c47ab 100644 --- a/Common/Tests/UI/Components/TextArea.test.tsx +++ b/Common/Tests/UI/Components/TextArea.test.tsx @@ -25,6 +25,7 @@ describe("TextArea", () => { tabIndex={1} error="error" autoFocus={true} + disableSpellCheck={false} />, ); const textarea: HTMLElement = getByRole("textbox"); @@ -150,4 +151,25 @@ describe("TextArea", () => { expect(getByDisplayValue("")).toBeInTheDocument(); expect(queryByDisplayValue("\n")).not.toBeInTheDocument(); }); + + test("enables spellcheck by default", () => { + const { getByRole } = render(