diff --git a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx index 8d012dedb..268eed76f 100644 --- a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx +++ b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx @@ -1,15 +1,15 @@ import React, { FC, useMemo, useRef, useState } from "preact/compat"; -import { getTimezoneList, getUTCByTimezone } from "../../../../utils/time"; +import { getBrowserTimezone, getTimezoneList, getUTCByTimezone } from "../../../../utils/time"; import { ArrowDropDownIcon } from "../../../Main/Icons"; import classNames from "classnames"; import Popper from "../../../Main/Popper/Popper"; import Accordion from "../../../Main/Accordion/Accordion"; -import dayjs from "dayjs"; import TextField from "../../../Main/TextField/TextField"; import { Timezone } from "../../../../types"; import "./style.scss"; import useDeviceDetect from "../../../../hooks/useDeviceDetect"; import useBoolean from "../../../../hooks/useBoolean"; +import WarningTimezone from "./WarningTimezone"; interface TimezonesProps { timezoneState: string; @@ -18,9 +18,12 @@ interface TimezonesProps { } interface PinnedTimezone extends Timezone { - title: string + title: string; + isInvalid?: boolean; } +const browserTimezone = getBrowserTimezone(); + const Timezones: FC = ({ timezoneState, defaultTimezone, onChange }) => { const { isMobile } = useDeviceDetect(); const timezones = getTimezoneList(); @@ -41,9 +44,10 @@ const Timezones: FC = ({ timezoneState, defaultTimezone, onChang utc: defaultTimezone ? getUTCByTimezone(defaultTimezone) : "UTC" }, { - title: `Browser Time (${dayjs.tz.guess()})`, - region: dayjs.tz.guess(), - utc: getUTCByTimezone(dayjs.tz.guess()) + title: browserTimezone.title, + region: browserTimezone.region, + utc: getUTCByTimezone(browserTimezone.region), + isInvalid: !browserTimezone.isValid }, { title: "UTC (Coordinated Universal Time)", @@ -132,7 +136,7 @@ const Timezones: FC = ({ timezoneState, defaultTimezone, onChang className="vm-timezones-item vm-timezones-list-group-options__item" onClick={createHandlerSetTimezone(t)} > -
{t.title}
+
{t.title}{t.isInvalid && }
{t.utc}
))} diff --git a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/WarningTimezone.tsx b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/WarningTimezone.tsx new file mode 100644 index 000000000..8231c5f7f --- /dev/null +++ b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/WarningTimezone.tsx @@ -0,0 +1,16 @@ +import React, { FC } from "preact/compat"; +import Tooltip from "../../../Main/Tooltip/Tooltip"; +import { WarningIcon } from "../../../Main/Icons"; + +const waringText = "Browser timezone is not recognized, supported, or could not be determined."; + +const WarningTimezone: FC = () => { + + return ( + + + + ); +}; + +export default WarningTimezone; diff --git a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/style.scss b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/style.scss index 512f24db3..506e5d87b 100644 --- a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/style.scss +++ b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/style.scss @@ -16,7 +16,15 @@ } &__title { + display: flex; + align-items: center; + gap: $padding-small; text-transform: capitalize; + + svg { + width: 14px; + color: $color-warning; + } } &__utc { diff --git a/app/vmui/packages/vmui/src/hooks/useFetchDefaultTimezone.ts b/app/vmui/packages/vmui/src/hooks/useFetchDefaultTimezone.ts index b2460a1d0..ed59a6ab8 100644 --- a/app/vmui/packages/vmui/src/hooks/useFetchDefaultTimezone.ts +++ b/app/vmui/packages/vmui/src/hooks/useFetchDefaultTimezone.ts @@ -4,6 +4,7 @@ import { useAppState } from "../state/common/StateContext"; import { useTimeDispatch } from "../state/time/TimeStateContext"; import { getFromStorage } from "../utils/storage"; import dayjs from "dayjs"; +import { getBrowserTimezone } from "../utils/time"; const disabledDefaultTimezone = Boolean(getFromStorage("DISABLED_DEFAULT_TIMEZONE")); @@ -15,7 +16,7 @@ const useFetchDefaultTimezone = () => { const [error, setError] = useState(""); const setTimezone = (timezoneStr: string) => { - const timezone = timezoneStr.toLowerCase() === "local" ? dayjs.tz.guess() : timezoneStr; + const timezone = timezoneStr.toLowerCase() === "local" ? getBrowserTimezone().region : timezoneStr; try { dayjs().tz(timezone).isValid(); timeDispatch({ type: "SET_DEFAULT_TIMEZONE", payload: timezone }); diff --git a/app/vmui/packages/vmui/src/state/time/reducer.ts b/app/vmui/packages/vmui/src/state/time/reducer.ts index a1d8aed80..75d3231b1 100644 --- a/app/vmui/packages/vmui/src/state/time/reducer.ts +++ b/app/vmui/packages/vmui/src/state/time/reducer.ts @@ -6,10 +6,10 @@ import { getDurationFromPeriod, getTimeperiodForDuration, getRelativeTime, - setTimezone + setTimezone, + getBrowserTimezone } from "../../utils/time"; import { getQueryStringValue } from "../../utils/query-string"; -import dayjs from "dayjs"; import { getFromStorage, saveToStorage } from "../../utils/storage"; export interface TimeState { @@ -29,7 +29,7 @@ export type TimeAction = | { type: "SET_TIMEZONE", payload: string } | { type: "SET_DEFAULT_TIMEZONE", payload: string } -const timezone = getFromStorage("TIMEZONE") as string || dayjs.tz.guess(); +const timezone = getFromStorage("TIMEZONE") as string || getBrowserTimezone().region; setTimezone(timezone); const defaultDuration = getQueryStringValue("g0.range_input") as string; diff --git a/app/vmui/packages/vmui/src/utils/time.ts b/app/vmui/packages/vmui/src/utils/time.ts index 0f2f5b78d..aff82f2aa 100644 --- a/app/vmui/packages/vmui/src/utils/time.ts +++ b/app/vmui/packages/vmui/src/utils/time.ts @@ -227,3 +227,22 @@ export const getTimezoneList = (search = "") => { export const setTimezone = (timezone: string) => { dayjs.tz.setDefault(timezone); }; + +const isValidTimezone = (timezone: string) => { + try { + dayjs().tz(timezone); + return true; + } catch (e) { + return false; + } +}; + +export const getBrowserTimezone = () => { + const timezone = dayjs.tz.guess(); + const isValid = isValidTimezone(timezone); + return { + isValid, + title: isValid ? `Browser Time (${timezone})` : "Browser timezone (UTC)", + region: isValid ? timezone : "UTC", + }; +}; diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d8d219f91..610b0fa1f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -35,6 +35,7 @@ The sandbox cluster installation is running under the constant load generated by * BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): properly propagate [label filters](https://docs.victoriametrics.com/keyconcepts/#filtering) from multiple arguments passed to [aggregate functions](https://docs.victoriametrics.com/metricsql/#aggregate-functions). For example, `sum({job="foo"}, {job="bar"}) by (job) + a` was improperly optimized to `sum({job="foo"}, {job="bar"}) by (job) + a{job="foo"}` before being executed. This could lead to unexpected results. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5604). * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix the graph dragging for Firefox and Safari. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5764). +* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix handling invalid timezone. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5732). ## [v1.97.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.97.1)