From f62715e9ffc079ec23be01b08694ca32d2ad7759 Mon Sep 17 00:00:00 2001 From: ssavutu Date: Fri, 31 Jul 2026 21:03:01 -0400 Subject: [PATCH] chore(frontend): point View Live at the configured public site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "View Live" link on the articles list built its URL from a hardcoded https://www.thetriangle.org, even though VITE_PUBLIC_SITE_URL already existed and was already plumbed through the frontend image as a build arg — the comments view and the editor's permalink preview both read it. Only this link did not, so it could send an editor to a different site than the rest of the CMS pointed at. Use publicSiteUrl() here too, and set the default to dev.thetriangle.org in both places that define it: the runtime fallback in urls.ts and the ARG in the frontend Dockerfile, which is what the published image actually gets since CI passes no build-arg. The CMS is not driving production yet, so an unconfigured build aimed at www would show editors pages that do not reflect what they just saved. The dashboard's "View site" button had the same hardcoded origin and is included — leaving it would have split the two buttons across two sites. No hardcoded origin remains in the frontend; verified in the built bundle. Co-Authored-By: Claude Opus 5 --- frontend/Dockerfile | 5 ++++- frontend/src/auth/urls.ts | 9 ++++++--- frontend/src/pages/DashboardPage.tsx | 3 ++- frontend/src/pages/articleView.tsx | 8 ++++++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 4543977..5603a97 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,7 +1,10 @@ FROM node:20-alpine AS builder WORKDIR /app -ARG VITE_PUBLIC_SITE_URL="https://www.thetriangle.org" +# Baked in at build time (Vite inlines import.meta.env), so this is the origin +# every "View Live" link and permalink preview in the published image points at. +# Override with --build-arg to publish an image aimed at another site. +ARG VITE_PUBLIC_SITE_URL="https://dev.thetriangle.org" ENV VITE_PUBLIC_SITE_URL=${VITE_PUBLIC_SITE_URL} COPY package.json package-lock.json ./ diff --git a/frontend/src/auth/urls.ts b/frontend/src/auth/urls.ts index df3a2d0..8535c00 100644 --- a/frontend/src/auth/urls.ts +++ b/frontend/src/auth/urls.ts @@ -10,8 +10,11 @@ export function authBaseUrl() { return trimTrailingSlashes(import.meta.env.VITE_AUTH_BASE_URL ?? "") } -// Public-facing site origin, used to build article permalinks (e.g. so Yoast can -// tell internal links from outbound ones). +// Public-facing site origin, used for article permalinks (e.g. so Yoast can +// tell internal links from outbound ones) and for the "View Live" links. +// Defaults to the dev site: the CMS is not yet driving production, so an +// unconfigured build pointing at www would send editors to pages that do not +// reflect what they just saved. export function publicSiteUrl() { - return trimTrailingSlashes(import.meta.env.VITE_PUBLIC_SITE_URL ?? "https://www.thetriangle.org") + return trimTrailingSlashes(import.meta.env.VITE_PUBLIC_SITE_URL ?? "https://dev.thetriangle.org") } diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index d47fb10..2c54292 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from "react" import { useNavigate } from "react-router-dom" import { useApiFetch } from "../hooks/useApiFetch" +import { publicSiteUrl } from "../auth/urls" import { useSessionAuth } from "../auth/sessionAuthContext" import { FileText, @@ -336,7 +337,7 @@ export default function DashboardPage() { variant="outline" size="sm" className="gap-1.5" - onClick={() => window.open("https://www.thetriangle.org", "_blank", "noopener,noreferrer")} + onClick={() => window.open(publicSiteUrl(), "_blank", "noopener,noreferrer")} > View site diff --git a/frontend/src/pages/articleView.tsx b/frontend/src/pages/articleView.tsx index f7a3d9b..49c1b58 100644 --- a/frontend/src/pages/articleView.tsx +++ b/frontend/src/pages/articleView.tsx @@ -1,6 +1,7 @@ -import { useEffect, useState } from "react" +import { useEffect, useMemo, useState } from "react" import { ExternalLink, Search, Pencil, Plus, Trash2, X, ChevronFirst, ChevronLast, ChevronLeft, ChevronRight, Undo2 } from "lucide-react" import { useNavigate } from "react-router-dom" +import { publicSiteUrl } from "../auth/urls" import { useApiFetch } from "../hooks/useApiFetch" type ArticleStatus = "Published" | "Draft" | "Archived" @@ -103,6 +104,9 @@ const writeSessionJSON = (key: string, value: unknown) => { function ArticleView({ pageTitle = "Articles", fixedType, excludeType }: ArticleViewProps) { const navigate = useNavigate() const apiFetch = useApiFetch() + // Same origin the comments view and the editor's permalink preview use, so + // "View Live" cannot point at a different site than the rest of the CMS. + const siteUrl = useMemo(() => publicSiteUrl(), []) const storageKeyBase = `articleView:${fixedType ?? "all"}:${excludeType ?? "none"}` const uiStateKey = `${storageKeyBase}:ui` const resultsCacheKey = `${storageKeyBase}:results` @@ -603,7 +607,7 @@ function ArticleView({ pageTitle = "Articles", fixedType, excludeType }: Article {activeTab !== "trash" && item.status === "Published" && (