diff --git a/frontend/package-lock.json b/frontend/package-lock.json index af368c0e5..42c99c60c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -49,7 +49,6 @@ "husky": "^9.0.11", "jsdom": "^24.0.0", "lodash": "^4.17.21", - "moment": "^2.30.1", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", "pretty-quick": "^4.0.0", @@ -8325,15 +8324,6 @@ "ufo": "^1.3.2" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 5d428ff92..df5b6918a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,7 +53,6 @@ "husky": "^9.0.11", "jsdom": "^24.0.0", "lodash": "^4.17.21", - "moment": "^2.30.1", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", "pretty-quick": "^4.0.0", diff --git a/frontend/src/pages/System/Status/index.tsx b/frontend/src/pages/System/Status/index.tsx index 80757c4c7..49c88ccd4 100644 --- a/frontend/src/pages/System/Status/index.tsx +++ b/frontend/src/pages/System/Status/index.tsx @@ -20,7 +20,6 @@ import { Text, } from "@mantine/core"; import { useDocumentTitle } from "@mantine/hooks"; -import moment from "moment"; import { FunctionComponent, PropsWithChildren, @@ -28,6 +27,13 @@ import { useCallback, useState, } from "react"; +import { + divisorDay, + divisorHour, + divisorMinute, + divisorSecond, + formatTime, +} from "@/utilities/time"; import Table from "./table"; interface InfoProps { @@ -98,15 +104,19 @@ const SystemStatusView: FunctionComponent = () => { const update = useCallback(() => { const startTime = status?.start_time; if (startTime) { - const duration = moment.duration( - moment().utc().unix() - startTime, - "seconds", - ), - days = duration.days(), - hours = duration.hours().toString().padStart(2, "0"), - minutes = duration.minutes().toString().padStart(2, "0"), - seconds = duration.seconds().toString().padStart(2, "0"); - setUptime(days + "d " + hours + ":" + minutes + ":" + seconds); + // Current time in seconds + const currentTime = Math.floor(Date.now() / 1000); + + const uptimeInSeconds = currentTime - startTime; + + const uptime: string = formatTime(uptimeInSeconds, [ + { unit: "d", divisor: divisorDay }, + { unit: "h", divisor: divisorHour }, + { unit: "m", divisor: divisorMinute }, + { unit: "s", divisor: divisorSecond }, + ]); + + setUptime(uptime); } }, [status?.start_time]); diff --git a/frontend/src/utilities/time.test.ts b/frontend/src/utilities/time.test.ts new file mode 100644 index 000000000..a0e936a25 --- /dev/null +++ b/frontend/src/utilities/time.test.ts @@ -0,0 +1,60 @@ +import { + divisorDay, + divisorHour, + divisorMinute, + divisorSecond, + formatTime, +} from "./time"; + +describe("formatTime", () => { + it("should format day hour minute and second", () => { + const uptimeInSeconds = 3661; + + const formattedTime = formatTime(uptimeInSeconds, [ + { unit: "d", divisor: divisorDay }, + { unit: "h", divisor: divisorHour }, + { unit: "m", divisor: divisorMinute }, + { unit: "s", divisor: divisorSecond }, + ]); + + expect(formattedTime).toBe("0d 01:01:01"); + }); + + it("should format multiple digits of days", () => { + const uptimeInSeconds = 50203661; + + const formattedTime = formatTime(uptimeInSeconds, [ + { unit: "d", divisor: divisorDay }, + { unit: "h", divisor: divisorHour }, + { unit: "m", divisor: divisorMinute }, + { unit: "s", divisor: divisorSecond }, + ]); + + expect(formattedTime).toBe("581d 25:27:41"); + }); + + it("should format time day hour minute", () => { + const uptimeInSeconds = 3661; + + const formattedTime = formatTime(uptimeInSeconds, [ + { unit: "d", divisor: divisorDay }, + { unit: "h", divisor: divisorHour }, + { unit: "m", divisor: divisorMinute }, + ]); + + expect(formattedTime).toBe("0d 01:01"); + }); + + it("should format zero uptime", () => { + const uptimeInSeconds = 0; + + const formattedTime = formatTime(uptimeInSeconds, [ + { unit: "d", divisor: divisorDay }, + { unit: "h", divisor: divisorHour }, + { unit: "m", divisor: divisorMinute }, + { unit: "s", divisor: divisorSecond }, + ]); + + expect(formattedTime).toBe("0d 00:00:00"); + }); +}); diff --git a/frontend/src/utilities/time.ts b/frontend/src/utilities/time.ts new file mode 100644 index 000000000..54f93289f --- /dev/null +++ b/frontend/src/utilities/time.ts @@ -0,0 +1,29 @@ +interface TimeFormat { + unit: string; + divisor: number; +} + +export const divisorDay = 24 * 60 * 60; +export const divisorHour = 60 * 60; +export const divisorMinute = 60; +export const divisorSecond = 1; + +export const formatTime = ( + timeInSeconds: number, + formats: TimeFormat[], +): string => + formats.reduce( + (formattedTime: string, { unit, divisor }: TimeFormat, index: number) => { + const timeValue: number = + index === 0 + ? Math.floor(timeInSeconds / divisor) + : Math.floor(timeInSeconds / divisor) % 60; + return ( + formattedTime + + (index === 0 + ? `${timeValue}${unit} ` + : `${timeValue.toString().padStart(2, "0")}${index < formats.length - 1 ? ":" : ""}`) + ); + }, + "", + );