diff --git a/.cache/gatsby-source-git/categories b/.cache/gatsby-source-git/categories new file mode 160000 index 000000000..a74c4062c --- /dev/null +++ b/.cache/gatsby-source-git/categories @@ -0,0 +1 @@ +Subproject commit a74c4062cc3eb40c01e0e0ad0d0740b453c99f94 diff --git a/app/[filename]/ServerRulePage.tsx b/app/[filename]/ServerRulePage.tsx index 062dd02d9..7f5418fc1 100644 --- a/app/[filename]/ServerRulePage.tsx +++ b/app/[filename]/ServerRulePage.tsx @@ -17,6 +17,7 @@ import RuleActionButtons from "@/components/RuleActionButtons"; import { YouTubeShorts } from "@/components/shared/Youtube"; import { getMarkdownComponentMapping } from "@/components/tina-markdown/markdown-component-mapping"; import { Card } from "@/components/ui/card"; +import IsrStatusBadge from "@/components/ui/isr-status-badge"; export interface ServerRulePageProps { rule: any; @@ -83,8 +84,11 @@ export default function ServerRulePage({ serverRulePageProps, tinaProps }: Serve {rule?.title} -
- +
+
+ + +
diff --git a/components/last-updated-by/index.tsx b/components/last-updated-by/index.tsx index 419f59467..1eea0817e 100644 --- a/components/last-updated-by/index.tsx +++ b/components/last-updated-by/index.tsx @@ -57,7 +57,7 @@ export default function GitHubMetadata({ owner = "tinacms", repo = "tina.io", pa }, [owner, repo, path]); if (loading) { - return
Loading last updated info...
; + return
Loading last updated info...
; } // If we have data with historyUrl, show it even if there's an error @@ -89,8 +89,8 @@ export default function GitHubMetadata({ owner = "tinacms", repo = "tina.io", pa ) : ( displayAuthorName )} - - {" "} + {" "} + {` ${lastUpdateInRelativeTime}.`} diff --git a/components/ui/isr-status-badge.tsx b/components/ui/isr-status-badge.tsx new file mode 100644 index 000000000..a72609198 --- /dev/null +++ b/components/ui/isr-status-badge.tsx @@ -0,0 +1,61 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import React from "react"; +import { cn } from "@/lib/utils"; +import Tooltip from "../tooltip/tooltip"; + +// x-nextjs-cache header values: +// - HIT: Served from cache (valid) +// - MISS: Just generated (fresh) +// - STALE: Serving old content while rebuilding +type CacheStatus = "live" | "stale" | "loading"; + +export default function IsrStatusBadge() { + const pathname = usePathname(); + const [status, setStatus] = React.useState("loading"); + + React.useEffect(() => { + let cancelled = false; + setStatus("loading"); + + const checkCache = async () => { + try { + const res = await fetch(window.location.href, { + method: "HEAD", + cache: "no-store", + }); + + const cacheHeader = res.headers.get("x-nextjs-cache")?.toUpperCase(); + + if (cancelled) return; + + // HIT or MISS = Live (green), STALE = Stale (orange) + if (cacheHeader === "STALE") { + setStatus("stale"); + } else { + setStatus("live"); + } + } catch { + if (!cancelled) setStatus("live"); // Default to live on error + } + }; + + checkCache(); + return () => { cancelled = true; }; + }, [pathname]); + + if (status === "loading") { + return