diff --git a/client/src/Pages/CreateMonitor/index.tsx b/client/src/Pages/CreateMonitor/index.tsx index 39543d072..95e6d9a29 100644 --- a/client/src/Pages/CreateMonitor/index.tsx +++ b/client/src/Pages/CreateMonitor/index.tsx @@ -57,6 +57,11 @@ import { FormSelectField } from "@/Components/inputs/forms/FormSelectField"; import { FormSliderField } from "@/Components/inputs/forms/FormSliderField"; import { FormSwitchField } from "@/Components/inputs/forms/FormSwitchField"; +const httpMethodOptions = HttpMethods.map((method) => ({ + value: method, + label: method, +})); + interface GeneralSettingsConfig { urlLabel: string; urlPlaceholder: string; @@ -375,6 +380,83 @@ const CreateMonitorPage = () => { [t] ); + const typeOptions = useMemo( + () => + SelectableMonitorTypes.map((type) => ({ + value: type, + label: t(`pages.common.monitors.monitorTypes.${monitorTypeLabelKey[type]}`), + description: t( + `pages.createMonitor.form.type.${monitorTypeLabelKey[type]}Description` + ), + })), + [t] + ); + + const strategyOptions = useMemo( + () => + PageSpeedStrategies.map((strategy) => ({ + value: strategy, + label: t(`pages.createMonitor.form.general.option.strategy.${strategy}`), + })), + [t] + ); + + const gameOptions = useMemo( + () => [ + { + value: "", + label: t("pages.createMonitor.form.general.option.game.placeholder"), + }, + ...Object.entries(games ?? {}).map(([key, game]) => ({ + value: key, + label: game.name, + })), + ], + [games, t] + ); + + const dnsRecordTypeOptions = useMemo( + () => + DnsRecordTypes.map((recordType) => ({ + value: recordType, + label: t( + `pages.createMonitor.form.general.option.dnsRecordType.value.${recordType}` + ), + })), + [t] + ); + + const intervalOptions = useMemo( + () => + MonitorIntervalOptions.map((option) => ({ + value: option.value, + label: t( + `pages.createMonitor.form.frequency.option.frequency.value.${option.labelKey}` + ), + })), + [t] + ); + + const matchMethodOptions = useMemo( + () => + MonitorMatchMethods.map((method) => ({ + value: method, + label: t(`pages.createMonitor.form.advanced.option.matchMethod.${method}`), + })), + [t] + ); + + const geoCheckIntervalOptions = useMemo( + () => + GeoCheckIntervalOptions.map((option) => ({ + value: option.value, + label: t( + `pages.createMonitor.form.geoChecks.option.interval.value.${option.labelKey}` + ), + })), + [t] + ); + return ( { rightContent={ ({ - value: type, - label: t( - `pages.common.monitors.monitorTypes.${monitorTypeLabelKey[type]}` - ), - description: t( - `pages.createMonitor.form.type.${monitorTypeLabelKey[type]}Description` - ), - }))} + options={typeOptions} /> } /> @@ -451,12 +525,7 @@ const CreateMonitorPage = () => { fieldLabel={t( "pages.createMonitor.form.general.option.strategy.label" )} - options={PageSpeedStrategies.map((strategy) => ({ - value: strategy, - label: t( - `pages.createMonitor.form.general.option.strategy.${strategy}` - ), - }))} + options={strategyOptions} fallbackValue={DefaultPageSpeedStrategy} /> )} @@ -477,18 +546,7 @@ const CreateMonitorPage = () => { ({ - value: key, - label: game.name, - })), - ]} + options={gameOptions} /> )} @@ -532,12 +590,7 @@ const CreateMonitorPage = () => { fieldLabel={t( "pages.createMonitor.form.general.option.dnsRecordType.label" )} - options={DnsRecordTypes.map((recordType) => ({ - value: recordType, - label: t( - `pages.createMonitor.form.general.option.dnsRecordType.value.${recordType}` - ), - }))} + options={dnsRecordTypeOptions} /> )} { fieldLabel={t( "pages.createMonitor.form.frequency.option.frequency.label" )} - options={MonitorIntervalOptions.map((option) => ({ - value: option.value, - label: t( - `pages.createMonitor.form.frequency.option.frequency.value.${option.labelKey}` - ), - }))} + options={intervalOptions} /> } /> @@ -729,10 +777,7 @@ const CreateMonitorPage = () => { setValue("jsonPath", ""); } }} - options={HttpMethods.map((method) => ({ - value: method, - label: method, - }))} + options={httpMethodOptions} /> { "pages.createMonitor.form.advanced.option.matchMethod.label" )} fallbackValue={DefaultMonitorMatchMethod} - options={MonitorMatchMethods.map((method) => ({ - value: method, - label: t( - `pages.createMonitor.form.advanced.option.matchMethod.${method}` - ), - }))} + options={matchMethodOptions} /> { fieldLabel={t( "pages.createMonitor.form.geoChecks.option.interval.label" )} - options={GeoCheckIntervalOptions.map((option) => ({ - value: option.value, - label: t( - `pages.createMonitor.form.geoChecks.option.interval.value.${option.labelKey}` - ), - }))} + options={geoCheckIntervalOptions} /> )} diff --git a/client/src/Pages/Settings/index.tsx b/client/src/Pages/Settings/index.tsx index 8564952ae..cc1472de2 100644 --- a/client/src/Pages/Settings/index.tsx +++ b/client/src/Pages/Settings/index.tsx @@ -35,7 +35,8 @@ import { type ThemeMode, type ChartType, } from "@/Features/UI/uiSlice.js"; -import timezones from "@/Utils/timezones.json"; +import { timezoneOptions } from "@/Utils/timezoneOptions"; +import type { TimezoneOption } from "@/Utils/timezoneOptions"; import type { RootState } from "@/Types/state"; import { CHECK_TTL_SENTINEL } from "@/Types/Check"; import { FormTextField } from "@/Components/inputs/forms/FormTextField"; @@ -43,11 +44,6 @@ import { FormSliderField } from "@/Components/inputs/forms/FormSliderField"; import { FormSwitchField } from "@/Components/inputs/forms/FormSwitchField"; import { FormNumberField } from "@/Components/inputs/forms/FormNumberField"; -interface Timezone { - id: string; - name: string; -} - interface SettingsResponse { settings: any; pagespeedKeySet: boolean; @@ -141,16 +137,10 @@ export const SettingsPage = () => { const user = useSelector((state: RootState) => state.auth.user); - // Convert timezones to match AutoComplete format (id instead of _id) - const timezoneOptions: Timezone[] = timezones.map((tz) => ({ - id: tz._id, - name: tz.name, - })); - const selectedTimezone = timezoneOptions.find((tz) => tz.id === selectedTimezoneId) ?? null; - const handleTimezoneChange = (newValue: Timezone | null) => { + const handleTimezoneChange = (newValue: TimezoneOption | null) => { if (!newValue?.id) return; dispatch(setTimezone({ timezone: newValue.id })); }; @@ -317,12 +307,12 @@ export const SettingsPage = () => { option.name} - isOptionEqualToValue={(option: Timezone, value: Timezone) => + getOptionLabel={(option: TimezoneOption) => option.name} + isOptionEqualToValue={(option: TimezoneOption, value: TimezoneOption) => option.id === value.id } - onChange={(_, newValue) => { - handleTimezoneChange(newValue as Timezone | null); + onChange={(_, newValue: TimezoneOption | null) => { + handleTimezoneChange(newValue); }} fieldLabel={t("pages.settings.form.timezone.option.timezone.label")} /> diff --git a/client/src/Pages/StatusPage/Create/index.tsx b/client/src/Pages/StatusPage/Create/index.tsx index 1d9614a5d..1a3a5c344 100644 --- a/client/src/Pages/StatusPage/Create/index.tsx +++ b/client/src/Pages/StatusPage/Create/index.tsx @@ -17,7 +17,7 @@ import { useGet, usePost, usePut, useDelete } from "@/Hooks/UseApi"; import type { Monitor } from "@/Types/Monitor"; import type { MonitorDisplayType, StatusPageResponse } from "@/Types/StatusPage"; import { getMonitorTypeLabel } from "@/Types/StatusPage"; -import timezones from "@/Utils/timezones.json"; +import { timezoneOptions } from "@/Utils/timezoneOptions"; import { useNavigate, useParams } from "react-router-dom"; import { mutate } from "swr"; import axios from "axios"; @@ -66,16 +66,6 @@ const monitorsUrl = (() => { return `/monitors/team?${params.toString()}`; })(); -interface TimezoneOption { - _id: string; - name: string; -} - -const timezoneOptions = timezones.map((tz: TimezoneOption) => ({ - id: tz._id, - name: tz.name, -})); - const buildStatusPageKey = (slug: string | null | undefined) => slug ? `/status-page/${slug}?type=uptime&type=infrastructure` : null; diff --git a/client/src/Utils/timezoneOptions.ts b/client/src/Utils/timezoneOptions.ts new file mode 100644 index 000000000..c937bdc14 --- /dev/null +++ b/client/src/Utils/timezoneOptions.ts @@ -0,0 +1,13 @@ +import timezones from "@/Utils/timezones.json"; + +export interface TimezoneOption { + id: string; + name: string; +} + +// timezones.json uses Mongo-style _id; remap once at module load to the +// { id, name } shape AutoComplete expects. +export const timezoneOptions: TimezoneOption[] = timezones.map((tz) => ({ + id: tz._id, + name: tz.name, +}));