Merge branch 'hybrid' into dev

This commit is contained in:
Owen
2025-08-18 15:29:23 -07:00
54 changed files with 3959 additions and 1319 deletions
@@ -59,6 +59,7 @@ import { useParams, useRouter } from "next/navigation";
import { QRCodeCanvas } from "qrcode.react";
import { useTranslations } from "next-intl";
import { build } from "@server/build";
type SiteType = "newt" | "wireguard" | "local";
@@ -142,7 +143,7 @@ export default function Page() {
{
id: "wireguard" as SiteType,
title: t("siteWg"),
description: t("siteWgDescription"),
description: build == "saas" ? t("siteWgDescriptionSaas") : t("siteWgDescription"),
disabled: true
}
]),
@@ -152,7 +153,7 @@ export default function Page() {
{
id: "local" as SiteType,
title: t("local"),
description: t("siteLocalDescription")
description: build == "saas" ? t("siteLocalDescriptionSaas") : t("siteLocalDescription")
}
])
]);
+176
View File
@@ -0,0 +1,176 @@
"use client";
import {
SettingsContainer,
SettingsSection,
SettingsSectionTitle as SectionTitle,
SettingsSectionBody,
SettingsSectionFooter
} from "@app/components/Settings";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { Alert } from "@app/components/ui/alert";
import { Button } from "@app/components/ui/button";
import {
Shield,
Zap,
RefreshCw,
Activity,
Wrench,
CheckCircle,
ExternalLink
} from "lucide-react";
import Link from "next/link";
export default async function ManagedPage() {
return (
<>
<SettingsSectionTitle
title="Managed Self-Hosted"
description="More reliable and low-maintenance self-hosted Pangolin server with extra bells and whistles"
/>
<SettingsContainer>
<SettingsSection>
<SettingsSectionBody>
<p className="text-muted-foreground mb-4">
<strong>Managed Self-Hosted Pangolin</strong> is a
deployment option designed for people who want
simplicity and extra reliability while still keeping
their data private and self-hosted.
</p>
<p className="text-muted-foreground mb-6">
With this option, you still run your own Pangolin
node — your tunnels, SSL termination, and traffic
all stay on your server. The difference is that
management and monitoring are handled through our
cloud dashboard, which unlocks a number of benefits:
</p>
<div className="grid gap-4 md:grid-cols-2 py-4">
<div className="space-y-3">
<div className="flex items-start gap-3">
<CheckCircle className="w-5 h-5 text-green-500 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium">
Simpler operations
</h4>
<p className="text-sm text-muted-foreground">
No need to run your own mail server
or set up complex alerting. You'll
get health checks and downtime
alerts out of the box.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<RefreshCw className="w-5 h-5 text-blue-500 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium">
Automatic updates
</h4>
<p className="text-sm text-muted-foreground">
The cloud dashboard evolves quickly,
so you get new features and bug
fixes without having to manually
pull new containers every time.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Wrench className="w-5 h-5 text-orange-500 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium">
Less maintenance
</h4>
<p className="text-sm text-muted-foreground">
No database migrations, backups, or
extra infrastructure to manage. We
handle that in the cloud.
</p>
</div>
</div>
</div>
<div className="space-y-3">
<div className="flex items-start gap-3">
<Activity className="w-5 h-5 text-purple-500 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium">
Cloud failover
</h4>
<p className="text-sm text-muted-foreground">
If your node goes down, your tunnels
can temporarily fail over to our
cloud points of presence until you
bring it back online.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Shield className="w-5 h-5 text-indigo-500 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium">
High availability (PoPs)
</h4>
<p className="text-sm text-muted-foreground">
You can also attach multiple nodes
to your account for redundancy and
better performance.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Zap className="w-5 h-5 text-yellow-500 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium">
Future enhancements
</h4>
<p className="text-sm text-muted-foreground">
We're planning to add more
analytics, alerting, and management
tools to make your deployment even
more robust.
</p>
</div>
</div>
</div>
</div>
<Alert
variant="neutral"
className="flex items-center gap-1"
>
Read the docs to learn more about the Managed
Self-Hosted option in our{" "}
<Link
href="https://docs.digpangolin.com/self-host/advanced/convert-to-managed"
target="_blank"
rel="noopener noreferrer"
className="hover:underline text-primary flex items-center gap-1"
>
documentation
<ExternalLink className="w-4 h-4" />
</Link>
.
</Alert>
</SettingsSectionBody>
<SettingsSectionFooter>
<Link
href="https://docs.digpangolin.com/self-host/advanced/convert-to-managed"
target="_blank"
rel="noopener noreferrer"
className="hover:underline text-primary flex items-center gap-1"
>
<Button>
Convert This Node to Managed Self-Hosted
</Button>
</Link>
</SettingsSectionFooter>
</SettingsSection>
</SettingsContainer>
</>
);
}
+13 -2
View File
@@ -13,10 +13,12 @@ import {
TicketCheck,
User,
Globe, // Added from 'dev' branch
MonitorUp // Added from 'dev' branch
MonitorUp, // Added from 'dev' branch
Zap
} from "lucide-react";
export type SidebarNavSection = { // Added from 'dev' branch
export type SidebarNavSection = {
// Added from 'dev' branch
heading: string;
items: SidebarNavItem[];
};
@@ -108,6 +110,15 @@ export const adminNavSections: SidebarNavSection[] = [
{
heading: "Admin",
items: [
...(build == "oss"
? [
{
title: "managedSelfhosted",
href: "/admin/managed",
icon: <Zap className="h-4 w-4" />
}
]
: []),
{
title: "sidebarAllUsers",
href: "/admin/users",
+31 -1
View File
@@ -6,7 +6,7 @@ import { OrgSelector } from "@app/components/OrgSelector";
import { cn } from "@app/lib/cn";
import { ListUserOrgsResponse } from "@server/routers/org";
import SupporterStatus from "@app/components/SupporterStatus";
import { ExternalLink, Server, BookOpenText } from "lucide-react";
import { ExternalLink, Server, BookOpenText, Zap } from "lucide-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useUserContext } from "@app/hooks/useUserContext";
@@ -20,6 +20,7 @@ import {
TooltipProvider,
TooltipTrigger
} from "@app/components/ui/tooltip";
import { build } from "@server/build";
interface LayoutSidebarProps {
orgId?: string;
@@ -73,6 +74,35 @@ export function LayoutSidebar({
<div className="px-2 pt-1">
{!isAdminPage && user.serverAdmin && (
<div className="pb-4">
{build === "oss" && (
<Link
href="/admin/managed"
className={cn(
"flex items-center rounded transition-colors text-muted-foreground hover:text-foreground text-sm w-full hover:bg-secondary/50 dark:hover:bg-secondary/20 rounded-md",
isSidebarCollapsed
? "px-2 py-2 justify-center"
: "px-3 py-1.5"
)}
title={
isSidebarCollapsed
? t("managedSelfhosted")
: undefined
}
>
<span
className={cn(
"flex-shrink-0",
!isSidebarCollapsed && "mr-2"
)}
>
<Zap className="h-4 w-4" />
</span>
{!isSidebarCollapsed && (
<span>{t("managedSelfhosted")}</span>
)}
</Link>
)}
<Link
href="/admin"
className={cn(
+1 -1
View File
@@ -25,5 +25,5 @@ export type Env = {
disableBasicWireguardSites: boolean;
enableClients: boolean;
hideSupporterKey: boolean;
},
}
};