From 9319a24718651b397491ce6e0f2957b5fbb9f497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abel=20Fern=C3=A1ndez?= <44572727+abefernan@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:34:24 +0200 Subject: [PATCH] Avoid reloading Tx view (#21) * Fix Tx routes params * Extract TxSheet as client component * Use shallow routing for spans --- app/@span/(.)[...span]/page.tsx | 29 +++++++++++------- app/[...span]/page.tsx | 6 +++- components/mermaid.tsx | 30 +++++++++++++++++-- components/{tx-data.tsx => tx-data/index.tsx} | 13 ++++---- components/tx-data/tx-sheet.tsx | 22 ++++++++++++++ 5 files changed, 81 insertions(+), 19 deletions(-) rename components/{tx-data.tsx => tx-data/index.tsx} (68%) create mode 100644 components/tx-data/tx-sheet.tsx diff --git a/app/@span/(.)[...span]/page.tsx b/app/@span/(.)[...span]/page.tsx index e58d055..a6af618 100644 --- a/app/@span/(.)[...span]/page.tsx +++ b/app/@span/(.)[...span]/page.tsx @@ -1,17 +1,24 @@ import TxData from "@/components/tx-data"; -import { Sheet, SheetContent } from "@/components/ui/sheet"; +import TxSheet from "@/components/tx-data/tx-sheet"; -export default function Tx({ params }: { params: { span: string[] } }) { - const [txId, spanId] = params.span; +const traceIdLength = 32; + +export default function Tx({ params }: { params: { span: [string] } }) { + //NOTE - the params are parsed because this catch-all route merges both traceId and spanId + const [txId, spanId] = + params.span[0].length > traceIdLength + ? [ + params.span[0].slice(0, traceIdLength), + params.span[0].slice(traceIdLength), + ] + : [params.span[0]]; return ( - - -
-
Transaction {txId}
- -
-
-
+ +
+
Transaction {txId}
+ +
+
); } diff --git a/app/[...span]/page.tsx b/app/[...span]/page.tsx index febffd3..f02b679 100644 --- a/app/[...span]/page.tsx +++ b/app/[...span]/page.tsx @@ -1,6 +1,10 @@ import TxData from "@/components/tx-data"; -export default function Tx({ params }: { params: { span: string[] } }) { +export default function Tx({ + params, +}: { + params: { span: [string, string | undefined] }; +}) { const [txId, spanId] = params.span; return ( diff --git a/components/mermaid.tsx b/components/mermaid.tsx index c13d40b..a9c7c56 100644 --- a/components/mermaid.tsx +++ b/components/mermaid.tsx @@ -2,6 +2,7 @@ import { cn } from "@/lib/utils"; import mermaid from "mermaid"; +import { usePathname } from "next/navigation"; import { useEffect, useState } from "react"; mermaid.initialize({ @@ -36,7 +37,13 @@ const htmlReplacer = { ] ?? "", }; -export default function Mermaid({ chart }: { chart: string }) { +type MermaidProps = { + chart: string; + setSpanId: (spanId: string | undefined) => void; +}; + +export default function Mermaid({ chart, setSpanId }: MermaidProps) { + const pathname = usePathname(); const [renderStage, setRenderStage] = useState< "server" | "browser" | "mermaid" >("server"); @@ -67,6 +74,25 @@ export default function Mermaid({ chart }: { chart: string }) { htmlReplacer.regex, htmlReplacer.fn, ); + + const span = msg.firstElementChild; + if (!span) { + continue; + } + + const linkToSpan = span.getAttribute("href"); + if (!linkToSpan) { + continue; + } + + span.addEventListener("click", (e) => { + e.preventDefault(); + + if (!pathname.endsWith(linkToSpan)) { + window.history.replaceState(null, "", linkToSpan); + setSpanId(linkToSpan.split("/").slice(-1)[0]); + } + }); } } @@ -74,7 +100,7 @@ export default function Mermaid({ chart }: { chart: string }) { }); return () => clearInterval(interval); - }, [renderStage]); + }, [pathname, renderStage, setSpanId]); return renderStage !== "server" ? (
diff --git a/components/tx-data.tsx b/components/tx-data/index.tsx similarity index 68% rename from components/tx-data.tsx rename to components/tx-data/index.tsx index e4ce46d..6aa33b8 100644 --- a/components/tx-data.tsx +++ b/components/tx-data/index.tsx @@ -2,27 +2,30 @@ import { useTx } from "@/hooks/api"; import { sequenceDiagramFromSpans } from "@/lib/mermaid"; -import Mermaid from "./mermaid"; +import { useState } from "react"; +import Mermaid from "../mermaid"; type TxDataProps = { txId: string; - spanId: string; + spanId: string | undefined; }; export default function TxData({ txId, spanId }: TxDataProps) { const { isPending, isFetching, error, data: tx } = useTx(txId); + const [spanIdToFind, setSpanIdToFind] = useState(spanId); if (isPending) return "Loading..."; if (error) return "An error has occurred: " + error.message; if (!tx) return "Couldn't find a Tx with id: " + txId; const mermaidChart = sequenceDiagramFromSpans(tx.spans); - - const span = tx.spans.find((span) => span.spanId === spanId); + const span = tx.spans.find((span) => span.spanId === spanIdToFind); return (
- {!isFetching ? : null} + {!isFetching ? ( + + ) : null} {span ? (
           {JSON.stringify(
diff --git a/components/tx-data/tx-sheet.tsx b/components/tx-data/tx-sheet.tsx
new file mode 100644
index 0000000..a4e5e42
--- /dev/null
+++ b/components/tx-data/tx-sheet.tsx
@@ -0,0 +1,22 @@
+"use client";
+
+import { Sheet, SheetContent } from "@/components/ui/sheet";
+import { useRouter } from "next/navigation";
+import { PropsWithChildren } from "react";
+
+export default function TxSheet({ children }: PropsWithChildren) {
+  const router = useRouter();
+
+  return (
+     {
+        if (!open) {
+          router.back();
+        }
+      }}
+    >
+      {children}
+    
+  );
+}