From 335ffecfb4b7119eae2ffc21c128af5a4e854b5c Mon Sep 17 00:00:00 2001 From: Dylan Decrulle Date: Mon, 25 Nov 2024 11:23:51 +0100 Subject: [PATCH] Refactor: Remove Moment.js dependency and replace with Intl.DateTimeFormat for better performance and maintainability --- web/package.json | 5 +-- web/src/ui/i18n/resources/de.tsx | 4 +- web/src/ui/i18n/resources/en.tsx | 4 +- web/src/ui/i18n/resources/es.tsx | 4 +- web/src/ui/i18n/resources/fi.tsx | 4 +- web/src/ui/i18n/resources/fr.tsx | 4 +- web/src/ui/i18n/resources/it.tsx | 4 +- web/src/ui/i18n/resources/nl.tsx | 4 +- web/src/ui/i18n/resources/no.tsx | 4 +- web/src/ui/i18n/resources/zh-CN.tsx | 4 +- web/src/ui/i18n/types.ts | 2 +- .../ui/pages/account/AccountKubernetesTab.tsx | 2 +- .../ui/pages/account/AccountStorageTab.tsx | 2 +- web/src/ui/pages/account/AccountVaultTab.tsx | 2 +- .../SecretsExplorer/SecretsExplorer.tsx | 2 +- .../pages/myServices/ClusterEventsDialog.tsx | 2 +- .../MyServicesCard/MyServicesRunningTime.tsx | 2 +- .../useMoment.ts => tools/useFormatedDate.ts} | 43 +++++++------------ web/yarn.lock | 5 --- 19 files changed, 33 insertions(+), 70 deletions(-) rename web/src/ui/{shared/useMoment.ts => tools/useFormatedDate.ts} (86%) diff --git a/web/package.json b/web/package.json index eb9719ffb..a1fd0974e 100644 --- a/web/package.json +++ b/web/package.json @@ -60,7 +60,7 @@ "keycloakify": "^11.3.29", "memoizee": "^0.4.17", "minimal-polyfills": "^2.2.3", - "moment": "^2.30.1", + "mui-icons-material-lazy": "^1.0.3", "oidc-spa": "^5.6.1", "onyxia-ui": "^6.2.1", "pathe": "^1.1.2", @@ -78,8 +78,7 @@ "xterm-addon-web-links": "^0.9.0", "xterm-addon-webgl": "^0.16.0", "yaml": "^2.6.0", - "zod": "^3.23.8", - "mui-icons-material-lazy": "^1.0.3" + "zod": "^3.23.8" }, "resolutions": { "@codemirror/view": "6.34.1" diff --git a/web/src/ui/i18n/resources/de.tsx b/web/src/ui/i18n/resources/de.tsx index c43644033..8e27a0dd4 100644 --- a/web/src/ui/i18n/resources/de.tsx +++ b/web/src/ui/i18n/resources/de.tsx @@ -943,9 +943,7 @@ Fühlen Sie sich frei, Ihre Kubernetes-Bereitstellungen zu erkunden und die Kont CommandBar: { ok: "Ok" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, Do MMMM${isSameYear ? "" : " YYYY"}, HH:mm`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/en.tsx b/web/src/ui/i18n/resources/en.tsx index 523904c21..4e966ca2c 100644 --- a/web/src/ui/i18n/resources/en.tsx +++ b/web/src/ui/i18n/resources/en.tsx @@ -923,9 +923,7 @@ Feel free to explore and take charge of your Kubernetes deployments! CommandBar: { ok: "Ok" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, MMMM Do${isSameYear ? "" : " YYYY"}, h:mm a`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/es.tsx b/web/src/ui/i18n/resources/es.tsx index 70715ebf0..2cf5160b6 100644 --- a/web/src/ui/i18n/resources/es.tsx +++ b/web/src/ui/i18n/resources/es.tsx @@ -937,9 +937,7 @@ export const translations: Translations<"en"> = { CommandBar: { ok: "Aceptar" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, MMMM Do${isSameYear ? "" : " YYYY"}, h:mm a`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/fi.tsx b/web/src/ui/i18n/resources/fi.tsx index efae3c409..987d51463 100644 --- a/web/src/ui/i18n/resources/fi.tsx +++ b/web/src/ui/i18n/resources/fi.tsx @@ -929,9 +929,7 @@ Tutustu vapaasti ja ota hallintaan Kubernetes-julkaisusi! CommandBar: { ok: "ok" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, Do MMMM${isSameYear ? "" : " YYYY"}, HH:mm`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/fr.tsx b/web/src/ui/i18n/resources/fr.tsx index 222dd7a3f..e43ba5844 100644 --- a/web/src/ui/i18n/resources/fr.tsx +++ b/web/src/ui/i18n/resources/fr.tsx @@ -947,9 +947,7 @@ N'hésitez pas à explorer et à prendre en main vos déploiements Kubernetes ! CommandBar: { ok: "ok" }, - moment: { - "date format": ({ isSameYear }) => - `dddd Do MMMM${isSameYear ? "" : " YYYY"} à H[h]mm`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/it.tsx b/web/src/ui/i18n/resources/it.tsx index a2addd1c4..1d93dc049 100644 --- a/web/src/ui/i18n/resources/it.tsx +++ b/web/src/ui/i18n/resources/it.tsx @@ -938,9 +938,7 @@ Sentiti libero di esplorare e prendere il controllo dei tuoi deployment Kubernet CommandBar: { ok: "ok" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, Do MMMM${isSameYear ? "" : " YYYY"}, HH:mm`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/nl.tsx b/web/src/ui/i18n/resources/nl.tsx index 1ee617356..85a73fbd8 100644 --- a/web/src/ui/i18n/resources/nl.tsx +++ b/web/src/ui/i18n/resources/nl.tsx @@ -940,9 +940,7 @@ Voel je vrij om te verkennen en de controle over je Kubernetes-implementaties te CommandBar: { ok: "ok" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, Do MMMM${isSameYear ? "" : " YYYY"}, HH:mm`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/no.tsx b/web/src/ui/i18n/resources/no.tsx index 699a06a1c..a57529117 100644 --- a/web/src/ui/i18n/resources/no.tsx +++ b/web/src/ui/i18n/resources/no.tsx @@ -934,9 +934,7 @@ Utforsk gjerne og ta kontroll over tjenestene du kjører på Kubernetes! CommandBar: { ok: "ok" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, Do MMMM${isSameYear ? "" : " YYYY"}, HH:mm`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/resources/zh-CN.tsx b/web/src/ui/i18n/resources/zh-CN.tsx index 67bc3445e..1934f7b1a 100644 --- a/web/src/ui/i18n/resources/zh-CN.tsx +++ b/web/src/ui/i18n/resources/zh-CN.tsx @@ -876,9 +876,7 @@ ${ CommandBar: { ok: "是" }, - moment: { - "date format": ({ isSameYear }) => - `dddd, MMMM Do${isSameYear ? "" : " YYYY"}, h:mm a`, + formatedDate: { past1: ({ divisorKey }) => { switch (divisorKey) { case "now": diff --git a/web/src/ui/i18n/types.ts b/web/src/ui/i18n/types.ts index 9a70e2380..d9ad537b4 100644 --- a/web/src/ui/i18n/types.ts +++ b/web/src/ui/i18n/types.ts @@ -80,7 +80,7 @@ export type ComponentKey = | import("ui/pages/dataExplorer/DataExplorer").I18n | import("ui/pages/dataExplorer/UrlInput").I18n | import("ui/shared/CommandBar").I18n - | import("ui/shared/useMoment").I18n + | import("ui/tools/useFormatedDate").I18n | import("ui/shared/CopyToClipboardIconButton").I18n | import("ui/shared/Datagrid/CustomDataGrid").I18n | import("ui/shared/Datagrid/CustomDataGridToolbarDensitySelector").I18n diff --git a/web/src/ui/pages/account/AccountKubernetesTab.tsx b/web/src/ui/pages/account/AccountKubernetesTab.tsx index d3d089b72..f1f409671 100644 --- a/web/src/ui/pages/account/AccountKubernetesTab.tsx +++ b/web/src/ui/pages/account/AccountKubernetesTab.tsx @@ -14,7 +14,7 @@ import { useConstCallback } from "powerhooks/useConstCallback"; import { IconButton } from "onyxia-ui/IconButton"; import { CircularProgress } from "onyxia-ui/CircularProgress"; import { useCoreState, useCore } from "core"; -import { useFromNow } from "ui/shared/useMoment"; +import { useFromNow } from "ui/tools/useFormatedDate"; import { getIconUrlByName } from "lazy-icons"; const CodeBlock = lazy(() => import("ui/shared/CodeBlock")); diff --git a/web/src/ui/pages/account/AccountStorageTab.tsx b/web/src/ui/pages/account/AccountStorageTab.tsx index 384445ac8..1b6ea4834 100644 --- a/web/src/ui/pages/account/AccountStorageTab.tsx +++ b/web/src/ui/pages/account/AccountStorageTab.tsx @@ -9,7 +9,7 @@ import { tss } from "tss"; import { assert } from "tsafe/assert"; import { saveAs } from "file-saver"; import { smartTrim } from "ui/tools/smartTrim"; -import { useFromNow } from "ui/shared/useMoment"; +import { useFromNow } from "ui/tools/useFormatedDate"; import { useCoreState, useCore } from "core"; import { declareComponentKeys } from "i18nifty"; import { useConstCallback } from "powerhooks/useConstCallback"; diff --git a/web/src/ui/pages/account/AccountVaultTab.tsx b/web/src/ui/pages/account/AccountVaultTab.tsx index c6d025b8a..92289f221 100644 --- a/web/src/ui/pages/account/AccountVaultTab.tsx +++ b/web/src/ui/pages/account/AccountVaultTab.tsx @@ -14,7 +14,7 @@ import { useConstCallback } from "powerhooks/useConstCallback"; import { IconButton } from "onyxia-ui/IconButton"; import { CircularProgress } from "onyxia-ui/CircularProgress"; import { useCoreState, useCore } from "core"; -import { useFromNow } from "ui/shared/useMoment"; +import { useFromNow } from "ui/tools/useFormatedDate"; import type { Link } from "type-route"; import { routes } from "ui/routes"; import { capitalize } from "tsafe/capitalize"; diff --git a/web/src/ui/pages/mySecrets/SecretsExplorer/SecretsExplorer.tsx b/web/src/ui/pages/mySecrets/SecretsExplorer/SecretsExplorer.tsx index 0d62cf9da..1437a31c5 100644 --- a/web/src/ui/pages/mySecrets/SecretsExplorer/SecretsExplorer.tsx +++ b/web/src/ui/pages/mySecrets/SecretsExplorer/SecretsExplorer.tsx @@ -26,7 +26,7 @@ import { SecretsExplorerButtonBar } from "./SecretsExplorerButtonBar"; import { DirectoryHeader } from "onyxia-ui/DirectoryHeader"; import { useDomRect } from "powerhooks/useDomRect"; import { ExplorerIcon } from "./ExplorerIcon"; -import { getFormattedDate } from "ui/shared/useMoment"; +import { getFormattedDate } from "ui/tools/useFormatedDate"; import { Dialog } from "onyxia-ui/Dialog"; import { useCallbackFactory } from "powerhooks/useCallbackFactory"; import { Deferred } from "evt/tools/Deferred"; diff --git a/web/src/ui/pages/myServices/ClusterEventsDialog.tsx b/web/src/ui/pages/myServices/ClusterEventsDialog.tsx index 9a61dba9d..9fd2e29a1 100644 --- a/web/src/ui/pages/myServices/ClusterEventsDialog.tsx +++ b/web/src/ui/pages/myServices/ClusterEventsDialog.tsx @@ -4,7 +4,7 @@ import { useEvt } from "evt/hooks"; import { Dialog } from "onyxia-ui/Dialog"; import { Button } from "onyxia-ui/Button"; import { useCoreState, useCore } from "core"; -import { fromNow } from "ui/shared/useMoment"; +import { fromNow } from "ui/tools/useFormatedDate"; import { tss } from "tss"; import { useWindowInnerSize } from "powerhooks/useWindowInnerSize"; import { assert } from "tsafe/assert"; diff --git a/web/src/ui/pages/myServices/MyServicesCards/MyServicesCard/MyServicesRunningTime.tsx b/web/src/ui/pages/myServices/MyServicesCards/MyServicesCard/MyServicesRunningTime.tsx index cd1384f3a..5f76050ed 100644 --- a/web/src/ui/pages/myServices/MyServicesCards/MyServicesCard/MyServicesRunningTime.tsx +++ b/web/src/ui/pages/myServices/MyServicesCards/MyServicesCard/MyServicesRunningTime.tsx @@ -2,7 +2,7 @@ import { memo } from "react"; import { tss } from "tss"; import { Icon } from "onyxia-ui/Icon"; import { Text } from "onyxia-ui/Text"; -import { useFromNow } from "ui/shared/useMoment"; +import { useFromNow } from "ui/tools/useFormatedDate"; import { getIconUrlByName } from "lazy-icons"; export type Props = { diff --git a/web/src/ui/shared/useMoment.ts b/web/src/ui/tools/useFormatedDate.ts similarity index 86% rename from web/src/ui/shared/useMoment.ts rename to web/src/ui/tools/useFormatedDate.ts index af741d54a..c1d9f51bf 100644 --- a/web/src/ui/shared/useMoment.ts +++ b/web/src/ui/tools/useFormatedDate.ts @@ -1,5 +1,4 @@ import { useMemo, useEffect, useReducer } from "react"; -import moment from "moment"; import { useLang, getTranslation, evtLang } from "ui/i18n"; import { assert } from "tsafe/assert"; import { declareComponentKeys } from "i18nifty"; @@ -8,13 +7,23 @@ export function getFormattedDate(params: { time: number }): string { const { time } = params; const date = new Date(time); + const lang = evtLang.state; const isSameYear = date.getFullYear() === new Date().getFullYear(); - const lang = evtLang.state; - const { t } = getTranslation("moment"); + // Options pour formater la date + const options: Intl.DateTimeFormatOptions = { + weekday: "long", + day: "numeric", + month: "long", + year: isSameYear ? undefined : "numeric", + hour: "numeric", + minute: "numeric" + }; + + const formattedDate = new Intl.DateTimeFormat(lang, options).format(date); - return moment(date).locale(lang).format(t("date format", { isSameYear })); + return formattedDate; } export function useFormattedDate(params: { time: number }): string { @@ -26,24 +35,6 @@ export function useFormattedDate(params: { time: number }): string { return useMemo(() => getFormattedDate({ time }), [time, lang]); } -export function useValidUntil(params: { millisecondsLeft: number }): string { - const { millisecondsLeft } = params; - - const { lang } = useLang(); - - const validUntil = useMemo( - () => - moment() - .locale(lang) - .add(millisecondsLeft, "milliseconds") - .calendar() - .toLowerCase(), - [lang, millisecondsLeft] - ); - - return validUntil; -} - export const { fromNow } = (() => { const { getUnits } = (() => { type Unit = { @@ -64,7 +55,7 @@ export const { fromNow } = (() => { const YEAR = 365 * DAY; function getUnits(): Unit[] { - const { t } = getTranslation("moment"); + const { t } = getTranslation("formatedDate"); return divisorKeys.map(divisorKey => ({ divisor: (() => { @@ -173,10 +164,6 @@ const divisorKeys = [ type DivisorKey = (typeof divisorKeys)[number]; const { i18n } = declareComponentKeys< - | { - K: "date format"; - P: { isSameYear: boolean }; - } | { K: "past1"; P: { divisorKey: DivisorKey }; @@ -193,5 +180,5 @@ const { i18n } = declareComponentKeys< K: "futureN"; P: { divisorKey: DivisorKey }; } ->()("moment"); +>()("formatedDate"); export type I18n = typeof i18n; diff --git a/web/yarn.lock b/web/yarn.lock index ccbb647bd..e74bde76b 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -5371,11 +5371,6 @@ minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -moment@^2.30.1: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"