Skip to content

Commit 6ea9acf

Browse files
committed
remove og image
1 parent 8b83b66 commit 6ea9acf

6 files changed

Lines changed: 687 additions & 613 deletions

File tree

cmd/relay-server/frontend.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (f *Frontend) servePortalHTMLWithSSR(w http.ResponseWriter) {
173173

174174
htmlContent := string(f.cachedPortalHTML)
175175
htmlContent = f.injectServerData(htmlContent)
176-
htmlContent = f.injectOGMetadata(htmlContent, "", "", "")
176+
htmlContent = f.injectOGMetadata(htmlContent, "", "")
177177

178178
w.Header().Set("Content-Type", "text/html; charset=utf-8")
179179
w.Header().Set("Cache-Control", "no-cache, must-revalidate")
@@ -217,25 +217,17 @@ func (f *Frontend) serveTunnelStatus(w http.ResponseWriter, r *http.Request) {
217217
utils.WriteAPIData(w, http.StatusOK, resp)
218218
}
219219

220-
func (f *Frontend) injectOGMetadata(htmlContent, title, description, imageURL string) string {
220+
func (f *Frontend) injectOGMetadata(htmlContent, title, description string) string {
221221
if title == "" {
222222
title = "Portal Proxy Gateway"
223223
}
224224
if description == "" {
225225
description = "Transform your local services into web-accessible endpoints. Instant access from anywhere."
226226
}
227-
if imageURL == "" {
228-
base := strings.TrimSuffix(f.server.PortalURL(), "/")
229-
if !strings.HasPrefix(base, "http") {
230-
base = "https://" + base
231-
}
232-
imageURL = base + "/portal.jpg"
233-
}
234227

235228
replacer := strings.NewReplacer(
236229
"[%OG_TITLE%]", html.EscapeString(title),
237230
"[%OG_DESCRIPTION%]", html.EscapeString(description),
238-
"[%OG_IMAGE_URL%]", html.EscapeString(imageURL),
239231
"[%RELEASE_VERSION%]", html.EscapeString(types.ReleaseVersion),
240232
)
241233
return replacer.Replace(htmlContent)
@@ -328,6 +320,5 @@ func frontendRootAssetPaths() []string {
328320
"/apple-touch-icon.png",
329321
"/web-app-manifest-192x192.png",
330322
"/web-app-manifest-512x512.png",
331-
"/portal.jpg",
332323
}
333324
}

frontend/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ High-signal constraints for the relay-server frontend. Only items expensive to r
2323
- Why: any tooling or script assuming `index.html` post-build will fail.
2424

2525
5. **HTML metadata placeholders must match between HTML and Go.**
26-
`index.html` (renamed to `portal.html`) contains `[%OG_TITLE%]`, `[%OG_DESCRIPTION%]`, `[%OG_IMAGE_URL%]`, `[%RELEASE_VERSION%]`. Server-side substitution happens in `cmd/relay-server/frontend.go`.
26+
`index.html` (renamed to `portal.html`) contains `[%OG_TITLE%]`, `[%OG_DESCRIPTION%]`, `[%RELEASE_VERSION%]`. Server-side substitution happens in `cmd/relay-server/frontend.go`.
2727
- Why: renaming a placeholder in one place without the other leaves raw placeholder strings in production HTML.
2828

2929
6. **Admin state reads are aggregated through `/admin/snapshot`.**

frontend/index.html

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@
1010
/>
1111
<meta property="og:title" content="[%OG_TITLE%]" />
1212
<meta property="og:description" content="[%OG_DESCRIPTION%]" />
13-
<meta property="og:image" content="[%OG_IMAGE_URL%]" />
14-
<meta name="twitter:card" content="summary_large_image" />
13+
<meta name="twitter:card" content="summary" />
1514
<meta name="twitter:title" content="[%OG_TITLE%]" />
1615
<meta name="twitter:description" content="[%OG_DESCRIPTION%]" />
17-
<meta name="twitter:image" content="[%OG_IMAGE_URL%]" />
1816
<meta name="portal-release-version" content="[%RELEASE_VERSION%]" />
1917
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
2018
<title>Portal - Local to web. Instant access.</title>

frontend/public/portal.jpg

-207 KB
Binary file not shown.

frontend/src/components/ServerListView.tsx

Lines changed: 72 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type ListServer = ClientServer | AdminServer;
2626

2727
interface OfficialRegistryRelay {
2828
url: string;
29-
status: "online" | "unreachable" | "unknown";
29+
status: "online" | "unreachable";
3030
version?: string;
3131
}
3232

@@ -42,6 +42,46 @@ const OFFICIAL_REGISTRY_SOURCE_URL =
4242
"https://raw.githubusercontent.com/gosuda/portal/main/registry.json";
4343
const REPOSITORY_URL = "https://github.com/gosuda/portal";
4444

45+
async function loadOfficialRegistryRelay(
46+
relayURL: string
47+
): Promise<OfficialRegistryRelay> {
48+
const domainURL = new URL(API_PATHS.sdk.domain, relayURL).toString();
49+
50+
try {
51+
const domain = await apiClient.get<RelayDomainResponse>(domainURL);
52+
return {
53+
url: relayURL,
54+
status: "online",
55+
version: typeof domain?.version === "string" ? domain.version.trim() : "",
56+
};
57+
} catch {
58+
return { url: relayURL, status: "unreachable", version: "" };
59+
}
60+
}
61+
62+
async function loadOfficialRegistryRelays(
63+
sourceURL: string
64+
): Promise<OfficialRegistryRelay[]> {
65+
const response = await fetch(sourceURL, {
66+
headers: { Accept: "application/json" },
67+
});
68+
if (!response.ok) {
69+
throw new Error(`registry request failed with status ${response.status}`);
70+
}
71+
72+
const document = (await response.json()) as OfficialRegistryDocument;
73+
const relayURLs = Array.isArray(document.relays)
74+
? document.relays.filter(
75+
(relay): relay is string =>
76+
typeof relay === "string" && relay.trim().length > 0
77+
)
78+
: [];
79+
80+
return Promise.all(
81+
relayURLs.map((relayURL) => loadOfficialRegistryRelay(relayURL.trim()))
82+
);
83+
}
84+
4585
interface ServerListViewProps {
4686
title?: string;
4787
searchQuery: string;
@@ -123,8 +163,9 @@ export function ServerListView({
123163
onLogout,
124164
}: ServerListViewProps) {
125165
const [showFilterModal, setShowFilterModal] = useState(false);
126-
const [officialRegistryRelays, setOfficialRegistryRelays] = useState<OfficialRegistryRelay[] | null>(null);
127-
const [officialRegistryFailed, setOfficialRegistryFailed] = useState(false);
166+
const [officialRegistryRelays, setOfficialRegistryRelays] = useState<
167+
OfficialRegistryRelay[] | null
168+
>(null);
128169
const [selectedLeaseIds, setSelectedLeaseIds] = useState<Set<string>>(
129170
new Set()
130171
);
@@ -205,65 +246,20 @@ export function ServerListView({
205246
}
206247

207248
let cancelled = false;
249+
setOfficialRegistryRelays(null);
208250

209-
const loadRelayVersion = async (
210-
relayURL: string
211-
): Promise<OfficialRegistryRelay> => {
212-
const trimmedURL = relayURL.trim();
213-
if (trimmedURL === "") {
214-
return { url: relayURL, status: "unknown", version: "" };
215-
}
216-
217-
try {
218-
const domainURL = new URL(API_PATHS.sdk.domain, trimmedURL).toString();
219-
const domain = await apiClient.get<RelayDomainResponse>(domainURL);
220-
return {
221-
url: trimmedURL,
222-
status: "online",
223-
version:
224-
typeof domain?.version === "string" ? domain.version.trim() : "",
225-
};
226-
} catch {
227-
return { url: trimmedURL, status: "unreachable", version: "" };
228-
}
229-
};
230-
231-
const loadOfficialRegistry = async () => {
232-
try {
233-
const response = await fetch(OFFICIAL_REGISTRY_SOURCE_URL, {
234-
headers: { Accept: "application/json" },
235-
});
236-
if (!response.ok) {
237-
throw new Error(`registry request failed with status ${response.status}`);
238-
}
239-
const document = (await response.json()) as OfficialRegistryDocument;
240-
if (cancelled) {
241-
return;
242-
}
243-
244-
const relayURLs = Array.isArray(document.relays)
245-
? document.relays.filter(
246-
(relay): relay is string =>
247-
typeof relay === "string" && relay.trim().length > 0
248-
)
249-
: [];
250-
const relays = await Promise.all(relayURLs.map(loadRelayVersion));
251-
if (cancelled) {
252-
return;
251+
void loadOfficialRegistryRelays(OFFICIAL_REGISTRY_SOURCE_URL)
252+
.then((relays) => {
253+
if (!cancelled) {
254+
setOfficialRegistryRelays(relays);
253255
}
254-
255-
setOfficialRegistryFailed(false);
256-
setOfficialRegistryRelays(relays);
257-
} catch (error) {
256+
})
257+
.catch((error) => {
258258
if (!cancelled) {
259259
console.error("Failed to load official registry", error);
260-
setOfficialRegistryFailed(true);
261260
setOfficialRegistryRelays([]);
262261
}
263-
}
264-
};
265-
266-
void loadOfficialRegistry();
262+
});
267263

268264
return () => {
269265
cancelled = true;
@@ -273,9 +269,7 @@ export function ServerListView({
273269
const isAllSelected =
274270
allLeaseIds.length > 0 &&
275271
allLeaseIds.every((id) => selectedLeaseIds.has(id));
276-
const officialRegistryURL = OFFICIAL_REGISTRY_SOURCE_URL;
277-
const officialRegistryAvailable =
278-
officialRegistryRelays !== null && officialRegistryRelays.length > 0;
272+
const officialRegistryAvailable = (officialRegistryRelays?.length ?? 0) > 0;
279273

280274
const handleSelectAll = () => {
281275
if (isAllSelected) {
@@ -466,19 +460,13 @@ export function ServerListView({
466460

467461
const gridClasses =
468462
"grid grid-cols-1 gap-6 p-4 min-[500px]:grid-cols-2 min-[500px]:p-6 md:grid-cols-3";
469-
470-
const serverGrid = (
471-
<div className={gridClasses}>
472-
{serverRows.length > 0 ? (
473-
serverRows.map(renderServerCard)
474-
) : (
475-
<div className="col-span-full py-12 text-center">
476-
<p className="text-lg text-text-muted">
477-
No servers match these filters
478-
</p>
479-
</div>
480-
)}
481-
</div>
463+
const serverCards = serverRows.map(renderServerCard);
464+
const serverGrid =
465+
serverCards.length > 0 ? (
466+
<div className={gridClasses}>{serverCards}</div>
467+
) : null;
468+
const noMatchingServersMessage = (
469+
<p className="text-lg text-text-muted">No servers match these filters</p>
482470
);
483471

484472
const searchBar = (
@@ -560,7 +548,13 @@ export function ServerListView({
560548
</div>
561549
</div>
562550
<div className="mx-auto flex w-full max-w-6xl flex-1 flex-col px-0 md:px-8">
563-
<main className="z-0 flex-1">{serverGrid}</main>
551+
<main className="z-0 flex-1">
552+
{serverGrid ?? (
553+
<div className="py-12 text-center">
554+
{noMatchingServersMessage}
555+
</div>
556+
)}
557+
</main>
564558
</div>
565559
</>
566560
) : (
@@ -612,9 +606,7 @@ export function ServerListView({
612606
0 services visible
613607
</div>
614608
<div className="flex flex-1 items-center justify-center py-12 text-center">
615-
<p className="text-lg text-text-muted">
616-
No servers match these filters
617-
</p>
609+
{noMatchingServersMessage}
618610
</div>
619611
</div>
620612
)}
@@ -639,7 +631,7 @@ export function ServerListView({
639631
</p>
640632
</div>
641633
<a
642-
href={officialRegistryURL}
634+
href={OFFICIAL_REGISTRY_SOURCE_URL}
643635
target="_blank"
644636
rel="noopener noreferrer"
645637
className="inline-flex h-10 items-center justify-center rounded-full bg-primary/12 px-4 text-sm font-semibold text-primary transition-colors hover:bg-primary/20"
@@ -648,7 +640,7 @@ export function ServerListView({
648640
</a>
649641
</div>
650642

651-
{officialRegistryRelays === null && !officialRegistryFailed ? (
643+
{officialRegistryRelays === null ? (
652644
<p className="mt-6 text-sm text-text-muted">
653645
Loading official registry...
654646
</p>
@@ -658,15 +650,10 @@ export function ServerListView({
658650
const statusLabel = {
659651
online: "ONLINE",
660652
unreachable: "OFFLINE",
661-
unknown: "UNKNOWN",
662653
}[relay.status];
663654
const statusClass = {
664-
online:
665-
"bg-primary/12 text-primary",
666-
unreachable:
667-
"bg-secondary text-text-muted",
668-
unknown:
669-
"bg-secondary text-text-muted",
655+
online: "bg-primary/12 text-primary",
656+
unreachable: "bg-secondary text-text-muted",
670657
}[relay.status];
671658

672659
return (

0 commit comments

Comments
 (0)