pagespeed cleanup

This commit is contained in:
Alex Holliday committed 2025-12-28 07:05:09 +00:00
1 parent 16aec18c28
commit df707ab194
8 files changed
+106 -127

No files matched your search

+42 -20
View File
@@ -1,31 +1,53 @@
import { monitorSchemaPageSpeed } from "@/validation/zod";
import humanInterval from "human-interval";
import type { IMonitor } from "@/types/monitor";
import ms from "ms";
import { useMemo } from "react";
import type { FormValues, SubmitValues } from "@/pages/pagespeed/PageSpeedForm";
import { z } from "zod";
export const useInitForm = ({
initialData,
}: {
initialData: Partial<z.infer<typeof monitorSchemaPageSpeed>> | undefined;
initialData: IMonitor | undefined;
}) => {
return useMemo(() => {
let humanInterval = "3 minutes";
if (initialData?.interval) {
const parsed = Number(initialData.interval);
if (!isNaN(parsed)) {
humanInterval = ms(parsed, { long: true });
}
}
const defaults: z.infer<typeof monitorSchemaPageSpeed> = {
type: "pagespeed",
url: initialData?.url || "",
n: initialData?.n || 3,
notificationChannels: initialData?.notificationChannels || [],
name: initialData?.name || "",
interval: humanInterval,
rejectUnauthorized: true,
const apiToForm = (apiData: IMonitor): FormValues => {
console.log(JSON.stringify(apiData));
return {
type: apiData.type,
url: apiData.url,
n: apiData.n,
notificationChannels: apiData.notificationChannels,
name: apiData.name,
interval: ms(apiData.interval, { long: true }),
rejectUnauthorized: apiData.rejectUnauthorized,
};
};
return { defaults };
const formToApi = (form: FormValues): SubmitValues => {
const submitData: SubmitValues = {
type: form.type,
url: form.url,
n: form.n,
notificationChannels: form.notificationChannels,
name: form.name,
interval: humanInterval(form.interval),
rejectUnauthorized: form.rejectUnauthorized,
};
return submitData;
};
const defaults: FormValues = initialData
? apiToForm(initialData)
: {
type: "pagespeed",
url: "",
n: 3,
notificationChannels: [],
name: "",
interval: "3 minutes",
rejectUnauthorized: true,
};
return { defaults, formToApi };
}, [initialData]);
};
+7 -18
View File
@@ -1,21 +1,14 @@
import { monitorSchemaPageSpeed } from "@/validation/zod";
import { useGet, usePatch } from "@/hooks/UseApi";
import { PageSpeedForm } from "@/pages/pagespeed/PageSpeedForm";
import { useParams } from "react-router";
import type { ApiResponse } from "@/types/api";
import humanInterval from "human-interval";
import { z } from "zod";
import { useNavigate } from "react-router";
import type { INotificationChannel } from "@/types/notification-channel";
import type { IMonitor } from "@/types/monitor";
import type { SubmitValues } from "@/pages/pagespeed/PageSpeedForm";
const PageSpeedConfigurePage = () => {
type FormValues = z.infer<typeof monitorSchemaPageSpeed>;
type SubmitValues = Omit<FormValues, "interval"> & {
interval: number | undefined;
};
const { id } = useParams();
const navigate = useNavigate();
const { response } = useGet<ApiResponse<INotificationChannel[]>>(
@@ -29,16 +22,12 @@ const PageSpeedConfigurePage = () => {
const { patch, loading, error } = usePatch<Partial<SubmitValues>, IMonitor>();
const onSubmit = async (data: FormValues) => {
let interval = humanInterval(data.interval);
if (!interval) interval = 180000;
const submitData = {
type: data.type,
name: data.name,
notificationChannels: data.notificationChannels,
interval,
};
const result = await patch(`/monitors/${id}`, submitData);
if (!monitor) {
return null;
}
const onSubmit = async (data: SubmitValues) => {
const result = await patch(`/monitors/${id}`, data);
if (result) {
navigate(`/pagespeed/${id}`);
} else {
+3 -12
View File
@@ -1,28 +1,19 @@
import { PageSpeedForm } from "@/pages/pagespeed/PageSpeedForm";
import humanInterval from "human-interval";
import { z } from "zod";
import { monitorSchema } from "@/validation";
import { useGet, usePost } from "@/hooks/UseApi";
import type { ApiResponse } from "@/types/api";
import { useNavigate } from "react-router";
import type { INotificationChannel } from "@/types/notification-channel";
import type { SubmitValues } from "@/pages/pagespeed/PageSpeedForm";
const UptimeCreatePage = () => {
type FormValues = z.infer<typeof monitorSchema>;
type SubmitValues = Omit<FormValues, "interval"> & {
interval: number | undefined;
};
const navigate = useNavigate();
const { response } = useGet<ApiResponse<INotificationChannel[]>>(
"/notification-channels"
);
const { post, loading, error } = usePost<SubmitValues>();
const onSubmit = async (data: FormValues) => {
let interval = humanInterval(data.interval);
if (!interval) interval = 60000;
const submitData = { ...data, interval };
const result = await post("/monitors", submitData);
const onSubmit = async (data: SubmitValues) => {
const result = await post("/monitors", data);
if (result) {
navigate("/pagespeed");
} else {
+17 -10
View File
@@ -13,7 +13,7 @@ import { Typography } from "@mui/material";
import { useEffect, useState, useRef } from "react";
import { useTranslation } from "react-i18next";
import { monitorSchemaPageSpeed } from "@/validation/zod";
import { monitorSchemaPageSpeed } from "@/validation";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import {
@@ -24,8 +24,15 @@ import {
} from "react-hook-form";
import { useTheme } from "@mui/material/styles";
import { useInitForm } from "@/hooks/forms/UseInitPageSpeedForm";
import type { IMonitor } from "@/types/monitor";
type FormValues = z.infer<typeof monitorSchemaPageSpeed>;
export type FormValues = z.infer<typeof monitorSchemaPageSpeed>;
export type SubmitValues = Omit<
z.infer<typeof monitorSchemaPageSpeed>,
"interval"
> & {
interval: number | undefined;
};
export const PageSpeedForm = ({
mode = "create",
@@ -35,14 +42,14 @@ export const PageSpeedForm = ({
loading,
}: {
mode?: "create" | "configure";
initialData?: Partial<FormValues>;
onSubmit: SubmitHandler<FormValues>;
initialData?: IMonitor;
onSubmit: SubmitHandler<SubmitValues>;
notificationOptions: any[];
loading: boolean;
}) => {
const { t } = useTranslation();
const theme = useTheme();
const { defaults } = useInitForm({ initialData: initialData });
const { defaults, formToApi } = useInitForm({ initialData: initialData });
const urlInputRef = useRef<HTMLInputElement>(null);
const [selectedProtocol, setSelectedProtocol] = useState<string>("https");
@@ -92,13 +99,13 @@ export const PageSpeedForm = ({
}
}, [selectedProtocol]);
const notificationChannels = useWatch({
control,
name: "notificationChannels",
});
const notificationChannels =
useWatch({ control, name: "notificationChannels" }) || [];
const submitForm = (data: FormValues) => onSubmit(formToApi(data) as any);
return (
<BasePage component={"form"} onSubmit={handleSubmit(onSubmit)}>
<BasePage component={"form"} onSubmit={handleSubmit(submitForm)}>
<ConfigBox
title={t("monitors.common.form.general.title")}
subtitle={t("monitors.pageSpeed.form.general.description")}
+1
View File
@@ -2,3 +2,4 @@ export * from "./zod";
export * from "./login";
export * from "./register";
export * from "./monitor";
export * from "./pagespeed";
+18 -17
View File
@@ -1,24 +1,25 @@
import { z } from "zod";
import humanInterval from "human-interval";
const urlRegex =
import ms from "ms";
export const urlRegex =
/^(https?:\/\/)?(localhost|([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|[a-zA-Z0-9-]+|(\d{1,3}\.){3}\d{1,3})(:\d{1,5})?(\/.*)?$/;
const durationSchema = z.string().superRefine((val, ctx) => {
// if (!val || val.trim() === "") return;
const ms = humanInterval(val);
export const durationSchema = (minInterval: number) =>
z.string().superRefine((val, ctx) => {
const milis = humanInterval(val);
if (!ms || isNaN(ms)) {
ctx.addIssue({
code: "custom",
message: "Invalid duration format",
});
} else if (ms < 10000) {
ctx.addIssue({
code: "custom",
message: "Minimum duration is 10 seconds",
});
}
});
if (!milis || isNaN(milis)) {
ctx.addIssue({
code: "custom",
message: "Invalid duration format",
});
} else if (milis < minInterval) {
ctx.addIssue({
code: "custom",
message: `Minimum duration is ${ms(minInterval, { long: true })}`,
});
}
});
export const monitorSchema = z
.object({
@@ -31,7 +32,7 @@ export const monitorSchema = z
port: z.coerce.number().optional(),
notificationChannels: z.array(z.string()).optional().default([]),
name: z.string().min(1, "Display name is required"),
interval: durationSchema,
interval: durationSchema(10000),
rejectUnauthorized: z.boolean().default(true),
})
.superRefine((data, ctx) => {
+15
View File
@@ -0,0 +1,15 @@
import { z } from "zod";
import { urlRegex, durationSchema } from "@/validation";
export const monitorSchemaPageSpeed = z.object({
type: z.string().min(1, "You must select an option"),
url: z.string().min(1, "URL is required").regex(urlRegex, "Invalid URL"),
n: z.coerce
.number({ message: "Number required" })
.min(1, "Minimum value is 1")
.max(25, "Maximum value is 25"),
notificationChannels: z.array(z.string()).optional().default([]),
name: z.string().min(1, "Display name is required"),
interval: durationSchema(180000),
rejectUnauthorized: z.boolean().default(true),
});
+3 -50
View File
@@ -6,44 +6,8 @@ import { MaintenanceRepeats } from "@/types/maintenance";
const urlRegex =
/^(https?:\/\/)?(localhost|([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|[a-zA-Z0-9-]+|(\d{1,3}\.){3}\d{1,3})(:\d{1,5})?(\/.*)?$/;
const durationSchema = z
.string()
.optional()
.superRefine((val, ctx) => {
if (!val || val.trim() === "") return;
const ms = humanInterval(val);
if (!ms || isNaN(ms)) {
ctx.addIssue({
code: "custom",
message: "Invalid duration format",
});
} else if (ms < 10000) {
ctx.addIssue({
code: "custom",
message: "Minimum duration is 10 seconds",
});
}
});
const durationSchemaPageSpeed = z
.string()
.optional()
.superRefine((val, ctx) => {
if (!val || val.trim() === "") return;
const ms = humanInterval(val);
if (!ms || isNaN(ms)) {
ctx.addIssue({
code: "custom",
message: "Invalid duration format",
});
} else if (ms < 180000) {
ctx.addIssue({
code: "custom",
message: "Minimum duration is 3 minutes",
});
}
});
// monitor duration schema moved to client/src/validation/monitor.ts
// pagespeed duration schema moved to client/src/validation/pagespeed.ts
const durationSchemaInfra = z
.string()
.optional()
@@ -73,18 +37,7 @@ const optionalString = <T extends z.ZodTypeAny>(schema: T) =>
// moved to client/src/validation/monitor.ts
export const monitorSchemaPageSpeed = z.object({
type: z.string().min(1, "You must select an option"),
url: z.string().min(1, "URL is required").regex(urlRegex, "Invalid URL"),
n: z.coerce
.number({ message: "Number required" })
.min(1, "Minimum value is 1")
.max(25, "Maximum value is 25"),
notificationChannels: z.array(z.string()).optional().default([]),
name: z.string().min(1, "Display name is required"),
interval: durationSchemaPageSpeed,
rejectUnauthorized: z.boolean().default(true),
});
// moved to client/src/validation/pagespeed.ts
export const monitorSchemaInfra = z.object({
type: z.string().min(1, "You must select an option"),
url: z.string().min(1, "URL is required").regex(urlRegex, "Invalid URL"),