Merge pull request #3277 from fosrl/dev

Fix middleware and suppoter footer
This commit is contained in:
Owen Schwartz
2026-06-14 14:44:33 -07:00
committed by GitHub
7 changed files with 177 additions and 177 deletions

View File

@@ -1294,16 +1294,14 @@ export async function getTraefikConfig(
}
};
// Assets router at higher priority so /_next files load without rewrite
// Assets router at higher priority so /_next files load without rewrite.
// Do NOT apply the path-rewrite middleware here — static assets must
// keep their original path; only the host headers are needed.
config_output.http.routers![
`bg-r${bgResource.resourceId}-assets-router`
] = {
entryPoints: [entrypoint],
middlewares: [
...routerMiddlewares,
uiRewriteMiddlewareName,
uiHeadersMiddlewareName
],
middlewares: [...routerMiddlewares, uiHeadersMiddlewareName],
service: bgUiServiceName,
rule: `${hostRule} && (PathPrefix(\`/_next\`) || PathRegexp(\`^/__nextjs*\`) || Path(\`/favicon.ico\`))`,
priority: 101,

View File

@@ -3,7 +3,6 @@ import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { response as sendResponse } from "@server/lib/response";
import config from "@server/lib/config";
import { build } from "@server/build";
import { APP_VERSION } from "@server/lib/consts";
import license from "#dynamic/license/license";
@@ -22,9 +21,6 @@ export async function getServerInfo(
next: NextFunction
): Promise<any> {
try {
const supporterData = config.getSupporterData();
const supporterStatusValid = supporterData?.valid || false;
let enterpriseLicenseValid = false;
let enterpriseLicenseType: string | null = null;
@@ -41,7 +37,7 @@ export async function getServerInfo(
return sendResponse<GetServerInfoResponse>(res, {
data: {
version: APP_VERSION,
supporterStatusValid,
supporterStatusValid: true,
build,
enterpriseLicenseValid,
enterpriseLicenseType

View File

@@ -42,7 +42,14 @@ import {
SettingsSectionFooter
} from "@app/components/Settings";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { ArrowRight, Check, ExternalLink, Heart, InfoIcon, TicketCheck } from "lucide-react";
import {
ArrowRight,
Check,
ExternalLink,
Heart,
InfoIcon,
TicketCheck
} from "lucide-react";
import Link from "next/link";
import DismissableBanner from "@app/components/DismissableBanner";
import CopyTextBox from "@app/components/CopyTextBox";
@@ -50,7 +57,7 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
import { SitePriceCalculator } from "@app/components/SitePriceCalculator";
import { Checkbox } from "@app/components/ui/checkbox";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { useSupporterStatusContext } from "@app/hooks/useSupporterStatusContext";
// import { useSupporterStatusContext } from "@app/hooks/useSupporterStatusContext";
import { useTranslations } from "next-intl";
const ENTERPRISE_DOCS_URL =
@@ -82,7 +89,7 @@ export default function LicensePage() {
const [isActivatingLicense, setIsActivatingLicense] = useState(false);
const [isDeletingLicense, setIsDeletingLicense] = useState(false);
const [isRecheckingLicense, setIsRecheckingLicense] = useState(false);
const { supporterStatus } = useSupporterStatusContext();
// const { supporterStatus } = useSupporterStatusContext();
const t = useTranslations();
@@ -347,9 +354,7 @@ export default function LicensePage() {
storageKey="license-banner-dismissed"
version={1}
title={t("licenseBannerTitle")}
titleIcon={
<TicketCheck className="w-5 h-5 text-primary" />
}
titleIcon={<TicketCheck className="w-5 h-5 text-primary" />}
description={t("licenseBannerDescription")}
>
<Link

View File

@@ -68,15 +68,15 @@ export default async function RootLayout({
const env = pullEnv();
const locale = await getLocale();
const supporterData = {
visible: true
} as any;
// const supporterData = {
// visible: true
// } as any;
const res = await priv.get<AxiosResponse<IsSupporterKeyVisibleResponse>>(
"supporter-key/visible"
);
supporterData.visible = res.data.data.visible;
supporterData.tier = res.data.data.tier;
// const res = await priv.get<AxiosResponse<IsSupporterKeyVisibleResponse>>(
// "supporter-key/visible"
// );
// supporterData.visible = res.data.data.visible;
// supporterData.tier = res.data.data.tier;
let licenseStatus: GetLicenseStatusResponse;
if (build === "enterprise") {
@@ -127,20 +127,20 @@ export default async function RootLayout({
<LicenseStatusProvider
licenseStatus={licenseStatus}
>
<SupportStatusProvider
{/* <SupportStatusProvider
supporterStatus={supporterData}
>
{/* Main content */}
<div className="h-full flex flex-col">
<div className="flex-1 overflow-auto">
<SplashImage>
<LicenseViolation />
{children}
</SplashImage>
> */}
{/* Main content */}
<div className="h-full flex flex-col">
<div className="flex-1 overflow-auto">
<SplashImage>
<LicenseViolation />
</div>
{children}
</SplashImage>
<LicenseViolation />
</div>
</SupportStatusProvider>
</div>
{/* </SupportStatusProvider> */}
</LicenseStatusProvider>
<Toaster />
</TanstackQueryProvider>

View File

@@ -1,24 +1,24 @@
"use client";
import { useSupporterStatusContext } from "@app/hooks/useSupporterStatusContext";
// import { useSupporterStatusContext } from "@app/hooks/useSupporterStatusContext";
import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
import { useTranslations } from "next-intl";
import { build } from "@server/build";
export default function AuthPageFooterNotices() {
const t = useTranslations();
const { supporterStatus } = useSupporterStatusContext();
// const { supporterStatus } = useSupporterStatusContext();
const { isUnlocked, licenseStatus } = useLicenseStatusContext();
return (
<>
{supporterStatus?.visible && (
{/* {supporterStatus?.visible && (
<div className="text-center mt-2">
<span className="text-sm text-muted-foreground opacity-50">
{t("noSupportKey")}
</span>
</div>
)}
)} */}
{build === "enterprise" && !isUnlocked() ? (
<div className="text-center mt-2">
<span className="text-sm font-medium text-muted-foreground">

View File

@@ -9,33 +9,34 @@ export default function SupporterMessage({ tier }: { tier: string }) {
const t = useTranslations();
return (
<div className="relative flex items-center space-x-2 whitespace-nowrap group">
<span
className="cursor-pointer"
onClick={(e) => {
// Get the bounding box of the element
const rect = (
e.target as HTMLElement
).getBoundingClientRect();
<></>
// <div className="relative flex items-center space-x-2 whitespace-nowrap group">
// <span
// className="cursor-pointer"
// onClick={(e) => {
// // Get the bounding box of the element
// const rect = (
// e.target as HTMLElement
// ).getBoundingClientRect();
// Trigger confetti centered on the word "Pangolin"
confetti({
particleCount: 100,
spread: 70,
origin: {
x: (rect.left + rect.width / 2) / window.innerWidth,
y: rect.top / window.innerHeight
},
colors: ["#FFA500", "#FF4500", "#FFD700"]
});
}}
>
Pangolin
</span>
<Star className="w-3 h-3" />
<div className="absolute left-1/2 transform -translate-x-1/2 -top-10 hidden group-hover:block text-primary text-sm rounded-md border shadow-md px-4 py-2 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity">
{t("componentsSupporterMessage", { tier: tier })}
</div>
</div>
// // Trigger confetti centered on the word "Pangolin"
// confetti({
// particleCount: 100,
// spread: 70,
// origin: {
// x: (rect.left + rect.width / 2) / window.innerWidth,
// y: rect.top / window.innerHeight
// },
// colors: ["#FFA500", "#FF4500", "#FFD700"]
// });
// }}
// >
// Pangolin
// </span>
// <Star className="w-3 h-3" />
// <div className="absolute left-1/2 transform -translate-x-1/2 -top-10 hidden group-hover:block text-primary text-sm rounded-md border shadow-md px-4 py-2 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity">
// {t("componentsSupporterMessage", { tier: tier })}
// </div>
// </div>
);
}

View File

@@ -3,7 +3,7 @@
// THIS IS DEPRECATED AND IS NO LONGER SHOWED TO THE USER WITH THE DISCONTINUATION
// OF THE SUPPORTER PROGRAM. IT MAY BE REMOVED IN A FUTURE UPDATE.
import { useSupporterStatusContext } from "@app/hooks/useSupporterStatusContext";
// import { useSupporterStatusContext } from "@app/hooks/useSupporterStatusContext";
import { useState, useTransition } from "react";
import {
Tooltip,
@@ -58,134 +58,134 @@ interface SupporterStatusProps {
export default function SupporterStatus({
isCollapsed = false
}: SupporterStatusProps) {
const { supporterStatus, updateSupporterStatus } =
useSupporterStatusContext();
const [supportOpen, setSupportOpen] = useState(false);
const [keyOpen, setKeyOpen] = useState(false);
const [purchaseOptionsOpen, setPurchaseOptionsOpen] = useState(false);
// const { supporterStatus, updateSupporterStatus } =
// useSupporterStatusContext();
// const [supportOpen, setSupportOpen] = useState(false);
// const [keyOpen, setKeyOpen] = useState(false);
// const [purchaseOptionsOpen, setPurchaseOptionsOpen] = useState(false);
const { env } = useEnvContext();
const api = createApiClient({ env });
const t = useTranslations();
// const { env } = useEnvContext();
// const api = createApiClient({ env });
// const t = useTranslations();
const formSchema = z.object({
githubUsername: z.string().nonempty({
error: "GitHub username is required"
}),
key: z.string().nonempty({
error: "Supporter key is required"
})
});
// const formSchema = z.object({
// githubUsername: z.string().nonempty({
// error: "GitHub username is required"
// }),
// key: z.string().nonempty({
// error: "Supporter key is required"
// })
// });
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
githubUsername: "",
key: ""
}
});
// const form = useForm({
// resolver: zodResolver(formSchema),
// defaultValues: {
// githubUsername: "",
// key: ""
// }
// });
async function hide() {
await api.post("/supporter-key/hide");
// async function hide() {
// await api.post("/supporter-key/hide");
updateSupporterStatus({
visible: false
});
}
// updateSupporterStatus({
// visible: false
// });
// }
async function onSubmit(values: z.infer<typeof formSchema>) {
try {
const res = await api.post<
AxiosResponse<ValidateSupporterKeyResponse>
>("/supporter-key/validate", {
githubUsername: values.githubUsername,
key: values.key
});
// async function onSubmit(values: z.infer<typeof formSchema>) {
// try {
// const res = await api.post<
// AxiosResponse<ValidateSupporterKeyResponse>
// >("/supporter-key/validate", {
// githubUsername: values.githubUsername,
// key: values.key
// });
const data = res.data.data;
// const data = res.data.data;
if (!data || !data.valid) {
toast({
variant: "destructive",
title: t("supportKeyInvalid"),
description: t("supportKeyInvalidDescription")
});
return;
}
// if (!data || !data.valid) {
// toast({
// variant: "destructive",
// title: t("supportKeyInvalid"),
// description: t("supportKeyInvalidDescription")
// });
// return;
// }
// Trigger the toast
toast({
variant: "default",
title: t("supportKeyValid"),
description: t("supportKeyValidDescription")
});
// // Trigger the toast
// toast({
// variant: "default",
// title: t("supportKeyValid"),
// description: t("supportKeyValidDescription")
// });
// Fireworks-style confetti
const duration = 5 * 1000; // 5 seconds
const animationEnd = Date.now() + duration;
const defaults = {
startVelocity: 30,
spread: 360,
ticks: 60,
zIndex: 0,
colors: ["#FFA500", "#FF4500", "#FFD700"] // Orange hues
};
// // Fireworks-style confetti
// const duration = 5 * 1000; // 5 seconds
// const animationEnd = Date.now() + duration;
// const defaults = {
// startVelocity: 30,
// spread: 360,
// ticks: 60,
// zIndex: 0,
// colors: ["#FFA500", "#FF4500", "#FFD700"] // Orange hues
// };
function randomInRange(min: number, max: number) {
return Math.random() * (max - min) + min;
}
// function randomInRange(min: number, max: number) {
// return Math.random() * (max - min) + min;
// }
const interval = setInterval(() => {
const timeLeft = animationEnd - Date.now();
// const interval = setInterval(() => {
// const timeLeft = animationEnd - Date.now();
if (timeLeft <= 0) {
clearInterval(interval);
return;
}
// if (timeLeft <= 0) {
// clearInterval(interval);
// return;
// }
const particleCount = 50 * (timeLeft / duration);
// const particleCount = 50 * (timeLeft / duration);
// Launch confetti from two random horizontal positions
confetti({
...defaults,
particleCount,
origin: {
x: randomInRange(0.1, 0.3),
y: Math.random() - 0.2
}
});
confetti({
...defaults,
particleCount,
origin: {
x: randomInRange(0.7, 0.9),
y: Math.random() - 0.2
}
});
}, 250);
// // Launch confetti from two random horizontal positions
// confetti({
// ...defaults,
// particleCount,
// origin: {
// x: randomInRange(0.1, 0.3),
// y: Math.random() - 0.2
// }
// });
// confetti({
// ...defaults,
// particleCount,
// origin: {
// x: randomInRange(0.7, 0.9),
// y: Math.random() - 0.2
// }
// });
// }, 250);
setPurchaseOptionsOpen(false);
setKeyOpen(false);
// setPurchaseOptionsOpen(false);
// setKeyOpen(false);
updateSupporterStatus({
visible: false
});
} catch (error) {
toast({
variant: "destructive",
title: t("error"),
description: formatAxiosError(
error,
t("supportKeyErrorValidationDescription")
)
});
return;
}
}
// updateSupporterStatus({
// visible: false
// });
// } catch (error) {
// toast({
// variant: "destructive",
// title: t("error"),
// description: formatAxiosError(
// error,
// t("supportKeyErrorValidationDescription")
// )
// });
// return;
// }
// }
return (
<>
<Credenza
{/* <Credenza
open={purchaseOptionsOpen}
onOpenChange={(val) => {
setPurchaseOptionsOpen(val);
@@ -469,7 +469,7 @@ export default function SupporterStatus({
{t("supportKeyBuy")}
</Button>
)
) : null}
) : null} */}
</>
);
}