feats(domain): configurable limit configs

This commit is contained in:
oiov
2025-06-19 21:15:35 +08:00
parent fd3567d48e
commit ae97fe895e
22 changed files with 171 additions and 43 deletions
+61
View File
@@ -80,6 +80,9 @@ export function DomainForm({
cf_record_types: initData?.cf_record_types || "CNAME,A,TXT",
cf_api_key_encrypted: initData?.cf_api_key_encrypted || false,
resend_api_key: initData?.resend_api_key || "",
min_url_length: initData?.min_url_length,
min_email_length: initData?.min_email_length,
min_record_length: initData?.min_record_length,
max_short_links: initData?.max_short_links || 0,
max_email_forwards: initData?.max_email_forwards || 0,
max_dns_records: initData?.max_dns_records || 0,
@@ -549,6 +552,64 @@ export function DomainForm({
</CollapsibleContent>
</Collapsible>
<Collapsible className="relative mt-2 rounded-md bg-neutral-100 p-4 dark:bg-neutral-800">
<CollapsibleTrigger className="flex w-full items-center justify-between">
<h2 className="absolute left-2 top-4 flex gap-2 text-xs font-semibold text-neutral-400">
{t("Limit Configs")} ({t("Optional")})
</h2>
<Icons.chevronDown className="ml-auto size-4" />
</CollapsibleTrigger>
<CollapsibleContent className="mt-3 space-y-2">
<div className="flex w-full items-center justify-between gap-2">
<Label className="cursor-pointer" htmlFor="min_url_length">
{t("Min URL Length")}:
</Label>
<Input
id="target"
className="max-w-20 flex-1 bg-neutral-50 shadow-inner"
size={32}
type="number"
defaultValue={initData?.min_url_length ?? 3}
{...register("min_url_length", {
valueAsNumber: true,
})}
/>
</div>
<div className="flex w-full items-center justify-between gap-2">
<Label className="cursor-pointer" htmlFor="min_email_length">
{t("Min Email Length")}:
</Label>
<Input
id="target"
className="max-w-20 flex-1 bg-neutral-50 shadow-inner"
size={32}
type="number"
defaultValue={initData?.min_email_length ?? 3}
{...register("min_email_length", {
valueAsNumber: true,
})}
/>
</div>
<div className="flex w-full items-center justify-between gap-2">
<Label className="cursor-pointer" htmlFor="min_subdomain_length">
{t("Min Subdomain Length")}:
</Label>
<Input
id="target"
className="max-w-20 flex-1 bg-neutral-50 shadow-inner"
size={32}
type="number"
defaultValue={initData?.min_record_length ?? 3}
{...register("min_record_length", {
valueAsNumber: true,
})}
/>
</div>
</CollapsibleContent>
</Collapsible>
{/* Action buttons */}
<div className="mt-3 flex justify-end gap-3">
{type === "edit" && (
+11 -1
View File
@@ -66,6 +66,7 @@ export function RecordForm({
initData?.type || "CNAME",
);
const [currentZoneName, setCurrentZoneName] = useState(initData?.zone_name);
const [limitLen, setLimitLen] = useState(3);
const [email, setEmail] = useState(initData?.user.email || user.email);
const [allowedRecordTypes, setAllowedRecordTypes] = useState<string[]>([]);
const isAdmin = action.indexOf("admin") > -1;
@@ -93,7 +94,11 @@ export function RecordForm({
// Fetch the record domains
const { data: recordDomains, isLoading } = useSWR<
{ domain_name: string; cf_record_types: string }[]
{
domain_name: string;
cf_record_types: string;
min_record_length: number;
}[]
>("/api/domain?feature=record", fetcher, {
revalidateOnFocus: false,
dedupingInterval: 10000,
@@ -131,6 +136,10 @@ export function RecordForm({
.find((d) => d.domain_name === validDefaultDomain)!
.cf_record_types.split(","),
);
setLimitLen(
recordDomains.find((d) => d.domain_name === currentZoneName)
?.min_record_length || 3,
);
}
}, [currentZoneName, recordDomains, validDefaultDomain]);
@@ -413,6 +422,7 @@ export function RecordForm({
id="name"
className="flex-1 shadow-inner"
size={32}
minLength={limitLen}
{...register("name")}
/>
{["CNAME", "A", "AAAA"].includes(currentRecordType) && (
+19 -8
View File
@@ -5,6 +5,7 @@ import {
SetStateAction,
useEffect,
useMemo,
useState,
useTransition,
} from "react";
import { zodResolver } from "@hookform/resolvers/zod";
@@ -58,6 +59,8 @@ export function UrlForm({
}: RecordFormProps) {
const [isPending, startTransition] = useTransition();
const [isDeleting, startDeleteTransition] = useTransition();
const [currentPrefix, setCurrentPrefix] = useState(initData?.prefix || "");
const [limitLen, setLimitLen] = useState(3);
const t = useTranslations("List");
const {
@@ -79,14 +82,12 @@ export function UrlForm({
},
});
const { data: shortDomains, isLoading } = useSWR<{ domain_name: string }[]>(
"/api/domain?feature=short",
fetcher,
{
revalidateOnFocus: false,
dedupingInterval: 10000,
},
);
const { data: shortDomains, isLoading } = useSWR<
{ domain_name: string; min_url_length: number }[]
>("/api/domain?feature=short", fetcher, {
revalidateOnFocus: false,
dedupingInterval: 10000,
});
const validDefaultDomain = useMemo(() => {
if (!shortDomains?.length) return undefined;
@@ -104,9 +105,17 @@ export function UrlForm({
useEffect(() => {
if (validDefaultDomain) {
setValue("prefix", validDefaultDomain);
setCurrentPrefix(validDefaultDomain);
}
}, [validDefaultDomain]);
useEffect(() => {
setLimitLen(
shortDomains?.find((d) => d.domain_name === currentPrefix)
?.min_url_length || 3,
);
}, [currentPrefix]);
const onSubmit = handleSubmit((data) => {
if (type === "add") {
handleCreateUrl(data);
@@ -233,6 +242,7 @@ export function UrlForm({
<Select
onValueChange={(value: string) => {
setValue("prefix", value);
setCurrentPrefix(value);
}}
name="prefix"
defaultValue={validDefaultDomain}
@@ -260,6 +270,7 @@ export function UrlForm({
id="url"
className="w-full rounded-none pl-[8px] shadow-inner"
size={20}
minLength={limitLen}
{...register("url")}
disabled={type === "edit"}
/>