mirror of
https://github.com/fosrl/pangolin.git
synced 2026-06-07 16:18:47 +00:00
All page types are there and look mostly correct
This commit is contained in:
@@ -27,6 +27,7 @@ type MultiSiteProps = {
|
||||
export type BrowserGatewayTargetFormProps = {
|
||||
orgId: string;
|
||||
destination: string;
|
||||
defaultPort: number;
|
||||
destinationPort: string;
|
||||
onDestinationChange: (v: string) => void;
|
||||
onDestinationPortChange: (v: string) => void;
|
||||
@@ -115,7 +116,7 @@ export function BrowserGatewayTargetForm(props: BrowserGatewayTargetFormProps) {
|
||||
<label className="text-sm font-semibold">{t("port")}</label>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="22"
|
||||
placeholder={props.defaultPort.toString()}
|
||||
value={props.destinationPort}
|
||||
onChange={(e) =>
|
||||
props.onDestinationPortChange(e.target.value)
|
||||
@@ -123,7 +124,7 @@ export function BrowserGatewayTargetForm(props: BrowserGatewayTargetFormProps) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{props.multiSite && (
|
||||
{props.multiSite === true && props.selectedSites.length > 1 && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("bgTargetMultiSiteDisclaimer")}{" "}
|
||||
<a
|
||||
|
||||
@@ -4,11 +4,9 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import {
|
||||
ShieldCheck,
|
||||
ShieldOff,
|
||||
Eye,
|
||||
EyeOff,
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
Clock
|
||||
XCircle
|
||||
} from "lucide-react";
|
||||
import { useResourceContext } from "@app/hooks/useResourceContext";
|
||||
import CopyToClipboard from "@app/components/CopyToClipboard";
|
||||
@@ -32,19 +30,40 @@ export default function ResourceInfoBox({}: ResourceInfoBoxType) {
|
||||
|
||||
const fullUrl = `${resource.ssl ? "https" : "http"}://${toUnicode(resource.fullDomain || "")}`;
|
||||
|
||||
const showCertificate = !!(
|
||||
resource.http &&
|
||||
resource.domainId &&
|
||||
resource.fullDomain &&
|
||||
build != "oss"
|
||||
);
|
||||
const showType = !!(resource.http && resource.browserAccessType);
|
||||
const showHealth =
|
||||
!["ssh", "rdp", "vnc"].includes(resource.browserAccessType || "") &&
|
||||
!!resource.health &&
|
||||
resource.health !== "unknown";
|
||||
const showVisibility = !resource.enabled;
|
||||
|
||||
const numSections = [
|
||||
true, // URL or Protocol
|
||||
true, // Authentication or Port
|
||||
showType,
|
||||
showCertificate,
|
||||
showHealth,
|
||||
showVisibility
|
||||
].filter(Boolean).length;
|
||||
|
||||
return (
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
{/* 4 cols because of the certs */}
|
||||
<InfoSections cols={resource.http && build != "oss" ? 6 : 5}>
|
||||
<InfoSection>
|
||||
<InfoSections cols={numSections}>
|
||||
{/* <InfoSection>
|
||||
<InfoSectionTitle>{t("identifier")}</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
<span className="inline-flex items-center">
|
||||
{resource.niceId}
|
||||
</span>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
</InfoSection> */}
|
||||
{resource.http ? (
|
||||
<>
|
||||
<InfoSection>
|
||||
@@ -62,6 +81,18 @@ export default function ResourceInfoBox({}: ResourceInfoBoxType) {
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
{showType && (
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("type")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
<span className="inline-flex items-center">
|
||||
{resource.browserAccessType!.toUpperCase()}
|
||||
</span>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
)}
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("authentication")}
|
||||
@@ -84,24 +115,6 @@ export default function ResourceInfoBox({}: ResourceInfoBoxType) {
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
{/* {isEnabled && (
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>Socket</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{isAvailable ? (
|
||||
<span className="flex items-center space-x-2">
|
||||
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
|
||||
<span>Online</span>
|
||||
</span>
|
||||
) : (
|
||||
<span className="flex items-center space-x-2">
|
||||
<div className="w-2 h-2 bg-neutral-500 rounded-full"></div>
|
||||
<span>Offline</span>
|
||||
</span>
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
)} */}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -149,74 +162,69 @@ export default function ResourceInfoBox({}: ResourceInfoBoxType) {
|
||||
{/* </InfoSectionContent> */}
|
||||
{/* </InfoSection> */}
|
||||
{/* Certificate Status Column */}
|
||||
{resource.http &&
|
||||
resource.domainId &&
|
||||
resource.fullDomain &&
|
||||
build != "oss" && (
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("certificateStatus", {
|
||||
defaultValue: "Certificate"
|
||||
})}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
<CertificateStatus
|
||||
orgId={resource.orgId}
|
||||
domainId={resource.domainId}
|
||||
fullDomain={resource.fullDomain}
|
||||
autoFetch={true}
|
||||
showLabel={false}
|
||||
polling={true}
|
||||
/>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
)}
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>{t("health")}</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{resource.health === "healthy" && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<CheckCircle2 className="w-4 h-4 flex-shrink-0 text-green-500" />
|
||||
<span>{t("resourcesTableHealthy")}</span>
|
||||
</div>
|
||||
)}
|
||||
{resource.health === "degraded" && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<CheckCircle2 className="w-4 h-4 flex-shrink-0 text-yellow-500" />
|
||||
<span>{t("resourcesTableDegraded")}</span>
|
||||
</div>
|
||||
)}
|
||||
{resource.health === "unhealthy" && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<XCircle className="w-4 h-4 flex-shrink-0 text-destructive" />
|
||||
<span>{t("resourcesTableUnhealthy")}</span>
|
||||
</div>
|
||||
)}
|
||||
{(!resource.health ||
|
||||
resource.health === "unknown") && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<Clock className="w-4 h-4 flex-shrink-0" />
|
||||
<span>{t("resourcesTableUnknown")}</span>
|
||||
</div>
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>{t("visibility")}</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{resource.enabled ? (
|
||||
<div className="flex items-center space-x-2">
|
||||
<Eye className="w-4 h-4 flex-shrink-0 text-green-500" />
|
||||
<span>{t("enabled")}</span>
|
||||
</div>
|
||||
) : (
|
||||
{showCertificate && (
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("certificateStatus", {
|
||||
defaultValue: "Certificate"
|
||||
})}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
<CertificateStatus
|
||||
orgId={resource.orgId}
|
||||
domainId={resource.domainId!}
|
||||
fullDomain={resource.fullDomain!}
|
||||
autoFetch={true}
|
||||
showLabel={false}
|
||||
polling={true}
|
||||
/>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
)}
|
||||
{showHealth && (
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>{t("health")}</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{resource.health === "healthy" && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<CheckCircle2 className="w-4 h-4 flex-shrink-0 text-green-500" />
|
||||
<span>
|
||||
{t("resourcesTableHealthy")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{resource.health === "degraded" && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<CheckCircle2 className="w-4 h-4 flex-shrink-0 text-yellow-500" />
|
||||
<span>
|
||||
{t("resourcesTableDegraded")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{resource.health === "unhealthy" && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<XCircle className="w-4 h-4 flex-shrink-0 text-destructive" />
|
||||
<span>
|
||||
{t("resourcesTableUnhealthy")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
)}
|
||||
{showVisibility && (
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("visibility")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
<div className="flex items-center space-x-2">
|
||||
<EyeOff className="w-4 h-4 flex-shrink-0 text-neutral-500" />
|
||||
<span>{t("disabled")}</span>
|
||||
</div>
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
)}
|
||||
</InfoSections>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
@@ -22,13 +22,24 @@ export function SettingsSectionHeader({
|
||||
|
||||
export function SettingsSectionForm({
|
||||
children,
|
||||
className
|
||||
className,
|
||||
variant = "compact"
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
variant?: "half" | "compact";
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("max-w-xl space-y-4", className)}>{children}</div>
|
||||
<div
|
||||
className={cn(
|
||||
variant === "half"
|
||||
? "max-w-3xl space-y-4"
|
||||
: "max-w-xl space-y-4",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user