Enhance domain validation feedback in ShowDomains and AddDomain components. Add descriptive tooltips for container port input and improve validation state messaging to indicate Cloudflare status. Remove unnecessary console logs for cleaner code.

This commit is contained in:
Mauricio Siu
2025-04-30 01:23:54 -06:00
parent bcebcfdfdf
commit 8ba4ac22cc
5 changed files with 42 additions and 15 deletions

View File

@@ -89,8 +89,6 @@ export const AddDomain = ({
serverId: application?.serverId || "", serverId: application?.serverId || "",
}); });
console.log("canGenerateTraefikMeDomains", canGenerateTraefikMeDomains);
const form = useForm<Domain>({ const form = useForm<Domain>({
resolver: zodResolver(domain), resolver: zodResolver(domain),
defaultValues: { defaultValues: {
@@ -276,6 +274,11 @@ export const AddDomain = ({
return ( return (
<FormItem> <FormItem>
<FormLabel>Container Port</FormLabel> <FormLabel>Container Port</FormLabel>
<FormDescription>
The port where your application is running inside the
container (e.g., 3000 for Node.js, 80 for Nginx, 8080
for Java)
</FormDescription>
<FormControl> <FormControl>
<NumberInput placeholder={"3000"} {...field} /> <NumberInput placeholder={"3000"} {...field} />
</FormControl> </FormControl>

View File

@@ -84,6 +84,7 @@ export const ShowDomains = ({ applicationId }: Props) => {
isValid: result.isValid, isValid: result.isValid,
error: result.error, error: result.error,
resolvedIp: result.resolvedIp, resolvedIp: result.resolvedIp,
message: result.error && result.isValid ? result.error : undefined,
}, },
})); }));
} catch (err) { } catch (err) {
@@ -304,7 +305,9 @@ export const ShowDomains = ({ applicationId }: Props) => {
) : validationState?.isValid ? ( ) : validationState?.isValid ? (
<> <>
<CheckCircle2 className="size-3 mr-1" /> <CheckCircle2 className="size-3 mr-1" />
{"DNS Valid"} {validationState.message
? "Behind Cloudflare"
: "DNS Valid"}
</> </>
) : validationState?.error ? ( ) : validationState?.error ? (
<> <>

View File

@@ -401,6 +401,11 @@ export const AddDomainCompose = ({
return ( return (
<FormItem> <FormItem>
<FormLabel>Container Port</FormLabel> <FormLabel>Container Port</FormLabel>
<FormDescription>
The port where your application is running inside the
container (e.g., 3000 for Node.js, 80 for Nginx, 8080
for Java)
</FormDescription>
<FormControl> <FormControl>
<NumberInput placeholder={"3000"} {...field} /> <NumberInput placeholder={"3000"} {...field} />
</FormControl> </FormControl>

View File

@@ -42,6 +42,7 @@ export type ValidationState = {
isValid?: boolean; isValid?: boolean;
error?: string; error?: string;
resolvedIp?: string; resolvedIp?: string;
message?: string;
}; };
export type ValidationStates = { export type ValidationStates = {
@@ -98,6 +99,7 @@ export const ShowDomainsCompose = ({ composeId }: Props) => {
isValid: result.isValid, isValid: result.isValid,
error: result.error, error: result.error,
resolvedIp: result.resolvedIp, resolvedIp: result.resolvedIp,
message: result.error && result.isValid ? result.error : undefined,
}, },
})); }));
} catch (err) { } catch (err) {
@@ -322,12 +324,14 @@ export const ShowDomainsCompose = ({ composeId }: Props) => {
) : validationState?.isValid ? ( ) : validationState?.isValid ? (
<> <>
<CheckCircle2 className="size-3 mr-1" /> <CheckCircle2 className="size-3 mr-1" />
{"DNS Valid"} {validationState.message
? "Behind Cloudflare"
: "DNS Valid"}
</> </>
) : validationState?.error ? ( ) : validationState?.error ? (
<> <>
<XCircle className="size-3 mr-1" /> <XCircle className="size-3 mr-1" />
{validationState.error} DNS Invalid
</> </>
) : ( ) : (
<> <>
@@ -338,13 +342,26 @@ export const ShowDomainsCompose = ({ composeId }: Props) => {
</Badge> </Badge>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent className="max-w-xs"> <TooltipContent className="max-w-xs">
{validationState?.error ? ( {validationState?.error &&
!validationState.isValid ? (
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<p className="font-medium text-red-500"> <p className="font-medium text-red-500">
Error: Error:
</p> </p>
<p>{validationState.error}</p> <p>{validationState.error}</p>
</div> </div>
) : validationState?.isValid ? (
<div className="flex flex-col gap-1">
<p className="font-medium text-green-500">
{validationState.message
? "Info:"
: "Valid Configuration:"}
</p>
<p>
{validationState.message ||
`Domain points to ${validationState.resolvedIp}`}
</p>
</div>
) : ( ) : (
"Click to validate DNS configuration" "Click to validate DNS configuration"
)} )}

View File

@@ -180,7 +180,7 @@ export const validateDomain = async (
// Resolve the domain to get its IP // Resolve the domain to get its IP
const ips = await resolveDns(cleanDomain || ""); const ips = await resolveDns(cleanDomain || "");
const resolvedIp = ips[0]; const resolvedIps = ips.map((ip) => ip.toString());
// Check if it's a Cloudflare IP // Check if it's a Cloudflare IP
const behindCloudflare = ips.some((ip) => isCloudflareIp(ip)); const behindCloudflare = ips.some((ip) => isCloudflareIp(ip));
@@ -189,7 +189,7 @@ export const validateDomain = async (
if (behindCloudflare) { if (behindCloudflare) {
return { return {
isValid: true, isValid: true,
resolvedIp, resolvedIp: resolvedIps.join(", "),
isCloudflare: true, isCloudflare: true,
error: error:
"Domain is behind Cloudflare - actual IP is masked by Cloudflare proxy", "Domain is behind Cloudflare - actual IP is masked by Cloudflare proxy",
@@ -199,19 +199,18 @@ export const validateDomain = async (
// If we have an expected IP, validate against it // If we have an expected IP, validate against it
if (expectedIp) { if (expectedIp) {
return { return {
isValid: resolvedIp === expectedIp, isValid: resolvedIps.includes(expectedIp),
resolvedIp, resolvedIp: resolvedIps.join(", "),
error: error: !resolvedIps.includes(expectedIp)
resolvedIp !== expectedIp ? `Domain resolves to ${resolvedIps.join(", ")} but should point to ${expectedIp}`
? `Domain resolves to ${resolvedIp} but should point to ${expectedIp}` : undefined,
: undefined,
}; };
} }
// If no expected IP, just return the resolved IP // If no expected IP, just return the resolved IP
return { return {
isValid: true, isValid: true,
resolvedIp, resolvedIp: resolvedIps.join(", "),
}; };
} catch (error) { } catch (error) {
return { return {