mirror of https://github.com/jetkvm/kvm.git
feat(ui): Improve StaticIpv4Card and StaticIpv6Card with IP address validation
This commit is contained in:
parent
59cfc25196
commit
9e09048f61
|
@ -1,13 +1,15 @@
|
||||||
import { LuPlus, LuX } from "react-icons/lu";
|
import { LuPlus, LuX } from "react-icons/lu";
|
||||||
import { useFieldArray, useFormContext } from "react-hook-form";
|
import { useFieldArray, useFormContext } from "react-hook-form";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import validator from "validator";
|
||||||
|
|
||||||
import { GridCard } from "@/components/Card";
|
import { GridCard } from "@/components/Card";
|
||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
import { InputFieldWithLabel } from "@/components/InputField";
|
import { InputFieldWithLabel } from "@/components/InputField";
|
||||||
|
import { NetworkSettings } from "@/hooks/stores";
|
||||||
|
|
||||||
export default function StaticIpv4Card() {
|
export default function StaticIpv4Card() {
|
||||||
const formMethods = useFormContext();
|
const formMethods = useFormContext<NetworkSettings>();
|
||||||
const { register, formState, watch } = formMethods;
|
const { register, formState, watch } = formMethods;
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({ name: "ipv4_static.dns" });
|
const { fields, append, remove } = useFieldArray({ name: "ipv4_static.dns" });
|
||||||
|
@ -17,6 +19,12 @@ export default function StaticIpv4Card() {
|
||||||
}, [append, fields.length]);
|
}, [append, fields.length]);
|
||||||
|
|
||||||
const dns = watch("ipv4_static.dns");
|
const dns = watch("ipv4_static.dns");
|
||||||
|
|
||||||
|
const validate = (value: string) => {
|
||||||
|
if (!validator.isIP(value)) return "Invalid IP address";
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridCard>
|
<GridCard>
|
||||||
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
||||||
|
@ -31,7 +39,8 @@ export default function StaticIpv4Card() {
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="192.168.1.100"
|
placeholder="192.168.1.100"
|
||||||
{...register("ipv4_static.address")}
|
{...register("ipv4_static.address", { validate })}
|
||||||
|
error={formState.errors.ipv4_static?.address?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InputFieldWithLabel
|
<InputFieldWithLabel
|
||||||
|
@ -39,7 +48,8 @@ export default function StaticIpv4Card() {
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="255.255.255.0"
|
placeholder="255.255.255.0"
|
||||||
{...register("ipv4_static.netmask")}
|
{...register("ipv4_static.netmask", { validate })}
|
||||||
|
error={formState.errors.ipv4_static?.netmask?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -48,7 +58,8 @@ export default function StaticIpv4Card() {
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="192.168.1.1"
|
placeholder="192.168.1.1"
|
||||||
{...register("ipv4_static.gateway")}
|
{...register("ipv4_static.gateway", { validate })}
|
||||||
|
error={formState.errors.ipv4_static?.gateway?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* DNS server fields */}
|
{/* DNS server fields */}
|
||||||
|
@ -63,14 +74,7 @@ export default function StaticIpv4Card() {
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="1.1.1.1"
|
placeholder="1.1.1.1"
|
||||||
{...register(`ipv4_static.dns.${index}`, {
|
{...register(`ipv4_static.dns.${index}`, { validate })}
|
||||||
// validate: (value: string) => {
|
|
||||||
// if (value === "") return true;
|
|
||||||
// if (!validator.isIP(value)) return "Invalid IP address";
|
|
||||||
// return true;
|
|
||||||
// },
|
|
||||||
})}
|
|
||||||
// @ts-expect-error - dns is not a field in the form
|
|
||||||
error={formState.errors.ipv4_static?.dns?.[index]?.message}
|
error={formState.errors.ipv4_static?.dns?.[index]?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,9 +6,10 @@ import { useEffect } from "react";
|
||||||
import { GridCard } from "@/components/Card";
|
import { GridCard } from "@/components/Card";
|
||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
import { InputFieldWithLabel } from "@/components/InputField";
|
import { InputFieldWithLabel } from "@/components/InputField";
|
||||||
|
import { NetworkSettings } from "@/hooks/stores";
|
||||||
|
|
||||||
export default function StaticIpv6Card() {
|
export default function StaticIpv6Card() {
|
||||||
const formMethods = useFormContext();
|
const formMethods = useFormContext<NetworkSettings>();
|
||||||
const { register, formState, watch } = formMethods;
|
const { register, formState, watch } = formMethods;
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({ name: "ipv6_static.dns" });
|
const { fields, append, remove } = useFieldArray({ name: "ipv6_static.dns" });
|
||||||
|
@ -18,6 +19,29 @@ export default function StaticIpv6Card() {
|
||||||
}, [append, fields.length]);
|
}, [append, fields.length]);
|
||||||
|
|
||||||
const dns = watch("ipv6_static.dns");
|
const dns = watch("ipv6_static.dns");
|
||||||
|
|
||||||
|
const cidrValidation = (value: string) => {
|
||||||
|
if (value === "") return true;
|
||||||
|
|
||||||
|
// Check if it's a valid IPv6 address with CIDR notation
|
||||||
|
const parts = value.split("/");
|
||||||
|
if (parts.length !== 2) return "Please use CIDR notation (e.g., 2001:db8::1/64)";
|
||||||
|
|
||||||
|
const [address, prefix] = parts;
|
||||||
|
if (!validator.isIP(address, 6)) return "Invalid IPv6 address";
|
||||||
|
const prefixNum = parseInt(prefix);
|
||||||
|
if (isNaN(prefixNum) || prefixNum < 0 || prefixNum > 128) {
|
||||||
|
return "Prefix must be between 0 and 128";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ipv6Validation = (value: string) => {
|
||||||
|
if (!validator.isIP(value, 6)) return "Invalid IPv6 address";
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridCard>
|
<GridCard>
|
||||||
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
||||||
|
@ -31,23 +55,7 @@ export default function StaticIpv6Card() {
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="2001:db8::1/64"
|
placeholder="2001:db8::1/64"
|
||||||
{...register("ipv6_static.address", {
|
{...register("ipv6_static.address", { validate: cidrValidation })}
|
||||||
validate: (value: string) => {
|
|
||||||
if (value === "") return true;
|
|
||||||
// Check if it's a valid IPv6 address with CIDR notation
|
|
||||||
const parts = value.split("/");
|
|
||||||
if (parts.length !== 2)
|
|
||||||
return "Please use CIDR notation (e.g., 2001:db8::1/64)";
|
|
||||||
const [address, prefix] = parts;
|
|
||||||
if (!validator.isIP(address, 6)) return "Invalid IPv6 address";
|
|
||||||
const prefixNum = parseInt(prefix);
|
|
||||||
if (isNaN(prefixNum) || prefixNum < 0 || prefixNum > 128) {
|
|
||||||
return "Prefix must be between 0 and 128";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
// @ts-expect-error - address is not a field in the form
|
|
||||||
error={formState.errors.ipv6_static?.address?.message}
|
error={formState.errors.ipv6_static?.address?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -56,7 +64,8 @@ export default function StaticIpv6Card() {
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="2001:db8::1"
|
placeholder="2001:db8::1"
|
||||||
{...register("ipv6_static.gateway")}
|
{...register("ipv6_static.gateway", { validate: ipv6Validation })}
|
||||||
|
error={formState.errors.ipv6_static?.gateway?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* DNS server fields */}
|
{/* DNS server fields */}
|
||||||
|
@ -72,13 +81,8 @@ export default function StaticIpv6Card() {
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="2001:4860:4860::8888"
|
placeholder="2001:4860:4860::8888"
|
||||||
{...register(`ipv6_static.dns.${index}`, {
|
{...register(`ipv6_static.dns.${index}`, {
|
||||||
validate: (value: string) => {
|
validate: ipv6Validation,
|
||||||
if (value === "") return true;
|
|
||||||
if (!validator.isIP(value)) return "Invalid IP address";
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
})}
|
})}
|
||||||
// @ts-expect-error - dns is not a field in the form
|
|
||||||
error={formState.errors.ipv6_static?.dns?.[index]?.message}
|
error={formState.errors.ipv6_static?.dns?.[index]?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue