Skip to content

Commit

Permalink
feat: various social image improvements
Browse files Browse the repository at this point in the history
# Why
 - There are some things I noticed after the review that we should clean up.
 - The ability to generate the image server-side is incredible. Folks can
   actually use this to link to the image from within documentation systems!

# What
 - Expose the feature more prominently in the share dialog
 - Clean up the URL paths to make this easier to discover
 - Some cleanup
  • Loading branch information
bripkens committed Dec 20, 2023
1 parent 2febc3c commit 52e69e2
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 66 deletions.
11 changes: 0 additions & 11 deletions packages/otelbin/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion packages/otelbin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.14.201",
"@types/node": "^18.18.13",
"@types/prettier": "^3.0.0",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^5.59.6",
Expand Down
2 changes: 2 additions & 0 deletions packages/otelbin/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
User-agent: *
Allow: /
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { getShortLinkPersistenceKey } from "~/lib/shortLink";
import type { IConfig } from "~/components/react-flow/dataType";
import { editorBinding } from "~/components/monaco-editor/editorBinding";
import JsYaml from "js-yaml";
import { calcScale, toUrlState } from "../../metadataUtils";
import Logo from "../../../../components/assets/svg/otelbin_logo_white.svg";
import { calcScale, toUrlState } from "../metadataUtils";
import Logo from "~/components/assets/svg/otelbin_logo_white.svg";
import { notFound } from "next/navigation";

export const runtime = "edge";

Expand All @@ -20,7 +21,7 @@ const edgeWidth = 80;
export async function GET(request: NextRequest) {
const shortLinkId = request.nextUrl.searchParams.get("id") ?? "";
if (!shortLinkId) {
return new NextResponse("No short link ID found in the request", { status: 400 });
return notFound();
}
const fullLink = (await redis.get<string>(getShortLinkPersistenceKey(shortLinkId))) ?? "";
let url;
Expand Down Expand Up @@ -75,7 +76,7 @@ export async function GET(request: NextRequest) {
{
width: 1200,
height: 630,
headers: { "Cache-Control": "public, max-age=3600, stale-while-revalidate=3600, stale-if-error=3600" },
headers: { "Cache-Control": "public, max-age=3600, stale-while-revalidate=604800, stale-if-error=604800" },
}
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// SPDX-License-Identifier: Apache-2.0

import { describe, expect, it } from "@jest/globals";
import { sortAndDeduplicate, extractComponents, calcScale, toUrlState } from "./metadataUtils";
import { calcScale, extractComponents, sortAndDeduplicate, toUrlState } from "./metadataUtils";
import type { IConfig } from "~/components/react-flow/dataType";
import { type Node } from "reactflow";
import { editorBinding } from "../../components/monaco-editor/editorBinding";
import { editorBinding } from "../../../components/monaco-editor/editorBinding";

describe("sortAndDeduplicate", () => {
it("should sort and deduplicate an array of strings and return a comma separated string of components", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { IConfig } from "~/components/react-flow/dataType";
import { type Node } from "reactflow";
import type { Binding } from "~/lib/urlState/binding";
import { parseUrlState } from "../../lib/urlState/parseUrlState";
import { parseUrlState } from "../../../lib/urlState/parseUrlState";
import type { Bindings } from "~/lib/urlState/typeMapping";

export function sortAndDeduplicate(arr: string[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { IConfig } from "~/components/react-flow/dataType";
import { getShortLinkPersistenceKey } from "~/lib/shortLink";
import { editorBinding } from "~/components/monaco-editor/editorBinding";
import JsYaml from "js-yaml";
import { extractComponents, sortAndDeduplicate, toUrlState } from "../metadataUtils";
import { extractComponents, sortAndDeduplicate, toUrlState } from "~/app/s/[id]/metadataUtils";
import { notFound } from "next/navigation";

interface ExtendedMetadata {
Expand Down Expand Up @@ -38,7 +38,7 @@ export async function generateMetadata({ params }: { params: { id: string } }):
return notFound();
}
const url = new URL(fullLink);
const imagesUrl = new URL(`/social-preview/${params.id}/img`, url.origin);
const imagesUrl = new URL(`/s/${params.id}/img`, url.origin);
const { config } = toUrlState(url, [editorBinding]);
const jsonData = JsYaml.load(config) as IConfig;
const components = extractComponents(jsonData);
Expand All @@ -47,7 +47,6 @@ export async function generateMetadata({ params }: { params: { id: string } }):
extendedMetadata.twitterData2 = sortAndDeduplicate(pipelines);

return {
metadataBase: new URL(url.origin),
openGraph: {
images: [
{
Expand Down
8 changes: 2 additions & 6 deletions packages/otelbin/src/app/s/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import { Redis } from "@upstash/redis";

const redis = Redis.fromEnv();

export async function GET(request: Request, { params }: { params: { id: string } }) {
export async function GET(_: Request, { params }: { params: { id: string } }) {
const shortLink = await redis.get<string>(getShortLinkPersistenceKey(params.id));
return NextResponse.redirect(shortLink || "/", {
headers: {
"Cache-Control": "public, max-age=3600, stale-while-revalidate=3600, stale-if-error=3600",
},
});
return NextResponse.redirect(shortLink || "/");
}
10 changes: 5 additions & 5 deletions packages/otelbin/src/app/s/new/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Redis } from "@upstash/redis";
import * as crypto from "crypto";
import { Ratelimit } from "@upstash/ratelimit";
import { type NextRequest, NextResponse } from "next/server";
import * as process from "process";
import { getShortLinkPersistenceKey } from "~/lib/shortLink";
import { getUserIdentifier } from "~/lib/userIdentifier";

Expand Down Expand Up @@ -55,13 +54,14 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
);
}

const uuid = crypto.randomUUID();
await redis.set(getShortLinkPersistenceKey(uuid), longURL);
const id = crypto.createHash("sha1").update(longURL).digest("hex");
await redis.set(getShortLinkPersistenceKey(id), longURL);

const shortURL = `${process.env.DEPLOYMENT_ORIGIN}/s/${uuid}`;
const shortURL = new URL(`/s/${id}`, request.nextUrl.origin);
return NextResponse.json(
{
shortLink: shortURL,
shortLink: shortURL.href,
imgURL: `${shortURL.href}/img`,
},
{
headers: {
Expand Down
67 changes: 50 additions & 17 deletions packages/otelbin/src/components/share/ShareContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function ShareContent() {
let fullURL = window.location.origin + getLink({});
const { isSignedIn } = useAuth();

const { data } = useSWRImmutable<{ shortLink: string }>(
const { data } = useSWRImmutable<{ shortLink: string; imgURL: string }>(
isSignedIn
? {
url: `/s/new`,
Expand All @@ -47,28 +47,52 @@ export function ShareContent() {
</SignInButton>
)}

{isSignedIn && (
<div className="mt-3 border-t-1 border-subtle px-4 pt-3">
<p className="weight mb-2 text-sm font-normal text-default">Link to this configuration with a badge.</p>
{data?.shortLink && (
<>
<div className="mt-3 border-t-1 border-subtle px-4 pt-3">
<p className="weight mb-2 text-sm font-normal text-default flex items-center justify-between">
Link to this configuration with a badge.
<Tooltip>
<TooltipTrigger asChild>
<IconButton size="xs" onClick={copyMarkdownToClipboard}>
<Copy />
</IconButton>
</TooltipTrigger>
<TooltipContent>Copy badge markdown to clipboard</TooltipContent>
</Tooltip>
</p>

<div className="flex gap-2 items-center">
<img
src="/badges/collector-config"
alt="OpenTelemetry collector configuration on OTelBin"
width={167}
height={20}
className="max-h-[20px] grow-0"
/>
<Tooltip>
<TooltipTrigger asChild>
<IconButton size="xs" onClick={copyToClipboard}>
<Copy />
</IconButton>
</TooltipTrigger>
<TooltipContent>Copy badge markdown to clipboard</TooltipContent>
</Tooltip>
</div>
</div>

<div className="mt-3 border-t-1 border-subtle px-4 pt-3">
<p className="weight mb-2 text-sm font-normal text-default flex items-center justify-between">
Link to an image of this visualization.
<Tooltip>
<TooltipTrigger asChild>
<IconButton size="xs" onClick={copyImageUrlToClipboard}>
<Copy />
</IconButton>
</TooltipTrigger>
<TooltipContent>Copy image URL to clipboard</TooltipContent>
</Tooltip>
</p>

<img
src={data.imgURL}
width={280}
height={147}
alt="OpenTelemetry collector configuration on OTelBin"
className="grow-0"
/>
</div>
</>
)}

<div className="mt-4 border-t-1 border-subtle px-4 py-3">
Expand All @@ -87,12 +111,22 @@ export function ShareContent() {
</div>
);

function copyToClipboard() {
function copyMarkdownToClipboard() {
const text = `[![OpenTelemetry collector configuration on OTelBin](${
window.location.origin + "/badges/collector-config"
})](${fullURL})`;
copyToClipboard(text);
track("Copied badge markdown");
}

function copyImageUrlToClipboard() {
copyToClipboard(data?.imgURL ?? "");
track("Copied image URL");
}

function copyToClipboard(value: string) {
navigator.clipboard
.writeText(text)
.writeText(value)
.then(() => {
toast({
description: "Copied to clipboard.",
Expand All @@ -104,6 +138,5 @@ export function ShareContent() {
description: "Failed to copy to clipboard",
});
});
track("Copied badge markdown");
}
}
23 changes: 7 additions & 16 deletions packages/otelbin/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
import { authMiddleware } from "@clerk/nextjs";
import { type NextRequest, NextResponse } from "next/server";
import { isBotRequest } from "./lib/utils";
import { notFound } from "next/navigation";

export default authMiddleware({
apiRoutes: ["/s/new"],
publicRoutes: ["/s/:id"],
afterAuth(auth, request: NextRequest) {
publicRoutes: (req) => req.nextUrl.pathname !== "/s/new",
afterAuth(_, request: NextRequest) {
return handleShortLinkRequest(request);
},
});
Expand All @@ -19,19 +18,11 @@ export const config = {
};

export async function handleShortLinkRequest(request: NextRequest) {
if (request.nextUrl.pathname.startsWith("/s") && !request.nextUrl.pathname.startsWith("/s/new")) {
const match = request.url.match(/\/s\/([^\/]+)$/);
const shortLink = match ? match[1] : "";

if (!shortLink) {
return notFound();
}

if (isBotRequest(request)) {
return NextResponse.rewrite(new URL(`/social-preview/${shortLink}`, request.url));
} else {
return NextResponse.next();
}
const shortLinkRegExp = /\/s\/([^/]+)$/;
const match = request.nextUrl.pathname.match(shortLinkRegExp);
if (match?.[1] && isBotRequest(request)) {
const shortLinkID = match[1];
return NextResponse.rewrite(new URL(`/s/${shortLinkID}/preview`, request.url));
} else {
return NextResponse.next();
}
Expand Down

0 comments on commit 52e69e2

Please sign in to comment.