fix: stabilize federation forward runtime cleanup and wire frontend version update UX

This commit is contained in:
sagitchu
2026-02-25 11:20:51 +08:00
parent 9c41410f17
commit 466cc65069
18 changed files with 665 additions and 66 deletions
@@ -55,7 +55,6 @@ export function SearchBar({
transition={{ duration: 0.18, ease: [0.25, 0.46, 0.45, 0.94] }}
>
<Input
autoFocus
classNames={{
base: "bg-default-100",
input:
+8 -2
View File
@@ -38,13 +38,19 @@ function Alert({
);
}
function AlertTitle({ className, ...props }: React.ComponentProps<"h5">) {
function AlertTitle({
className,
children,
...props
}: React.ComponentProps<"h5">) {
return (
<h5
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
data-slot="alert-title"
{...props}
/>
>
{children}
</h5>
);
}
+8 -2
View File
@@ -25,7 +25,11 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
);
}
function CardTitle({ className, ...props }: React.ComponentProps<"h3">) {
function CardTitle({
className,
children,
...props
}: React.ComponentProps<"h3">) {
return (
<h3
className={cn(
@@ -34,7 +38,9 @@ function CardTitle({ className, ...props }: React.ComponentProps<"h3">) {
)}
data-slot="card-title"
{...props}
/>
>
{children}
</h3>
);
}
@@ -0,0 +1,110 @@
import { useEffect, useState } from "react";
import { siteConfig } from "@/config/site";
import {
UPDATE_CHANNEL_CHANGED_EVENT,
type UpdateReleaseChannel,
getLatestVersionByChannel,
getUpdateReleaseChannel,
hasVersionUpdate,
} from "@/utils/version-update";
const FALLBACK_GITHUB_REPO = "https://github.com/Sagit-chu/flux-panel";
interface VersionFooterProps {
version: string;
containerClassName?: string;
versionClassName?: string;
poweredClassName?: string;
updateBadgeClassName?: string;
}
export function VersionFooter({
version,
containerClassName,
versionClassName,
poweredClassName,
updateBadgeClassName,
}: VersionFooterProps) {
const [channel, setChannel] = useState<UpdateReleaseChannel>(
getUpdateReleaseChannel(),
);
const [updateAvailable, setUpdateAvailable] = useState(false);
const [latestUpdateVersion, setLatestUpdateVersion] = useState<string | null>(
null,
);
useEffect(() => {
const handleChannelChange = () => {
setChannel(getUpdateReleaseChannel());
};
window.addEventListener(UPDATE_CHANNEL_CHANGED_EVENT, handleChannelChange);
window.addEventListener("storage", handleChannelChange);
return () => {
window.removeEventListener(
UPDATE_CHANNEL_CHANGED_EVENT,
handleChannelChange,
);
window.removeEventListener("storage", handleChannelChange);
};
}, []);
useEffect(() => {
let active = true;
const checkUpdate = async () => {
const latestVersion = await getLatestVersionByChannel(
channel,
siteConfig.github_repo || FALLBACK_GITHUB_REPO,
);
if (!active) {
return;
}
if (!latestVersion) {
setUpdateAvailable(false);
setLatestUpdateVersion(null);
return;
}
const hasUpdate = hasVersionUpdate(version, latestVersion);
setUpdateAvailable(hasUpdate);
setLatestUpdateVersion(hasUpdate ? latestVersion : null);
};
void checkUpdate();
return () => {
active = false;
};
}, [channel, version]);
return (
<div className={containerClassName}>
<p className={versionClassName}>
v{version}
{updateAvailable && latestUpdateVersion && (
<span className={updateBadgeClassName} role="status">
{latestUpdateVersion}
</span>
)}
</p>
<p className={poweredClassName}>
Powered by{" "}
<a
className="text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
href={siteConfig.github_repo}
rel="noopener noreferrer"
target="_blank"
>
FLVX
</a>
</p>
</div>
);
}