Skip to content

Commit

Permalink
Network tracking PR
Browse files Browse the repository at this point in the history
  • Loading branch information
AlemTuzlak committed Nov 5, 2024
1 parent 1129840 commit 8cefe29
Show file tree
Hide file tree
Showing 43 changed files with 2,056 additions and 1,889 deletions.
2,595 changes: 821 additions & 1,774 deletions package-lock.json

Large diffs are not rendered by default.

33 changes: 22 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
"require": "./dist/client.css"
}
},
"files": ["dist"],
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "git+https://github.com/forge42dev/react-router-devtools.git"
Expand Down Expand Up @@ -90,18 +92,22 @@
"icons": "npm run run:scripts scripts/icons.ts",
"check:unused": "knip "
},
"workspaces": [".", "test-apps/*"],
"workspaces": [
".",
"test-apps/*"
],
"peerDependencies": {
"react": ">=17",
"react-dom": ">=17",
"vite": ">=5.0.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@react-router/dev": "7.0.0-pre.1",
"@react-router/node": "7.0.0-pre.1",
"@react-router/serve": "7.0.0-pre.1",
"@react-router/dev": "7.0.0-pre.2",
"@react-router/node": "7.0.0-pre.2",
"@react-router/serve": "7.0.0-pre.2",
"@testing-library/react": "^16.0.1",
"@types/babel__core": "^7.20.5",
"@types/beautify": "^0.0.3",
"@types/node": "^20.16.14",
"@types/react": "^18.3.11",
Expand All @@ -119,24 +125,29 @@
"tailwind-merge": "^2.5.4",
"tailwindcss": "^3.4.14",
"tailwindcss-animate": "^1.0.7",
"tsup": "^8.3.0",
"tsx": "^4.19.1",
"tsup": "^8.3.5",
"tsx": "^4.19.2",
"typescript": "^5.6.3",
"vite": "^5.4.9",
"vite": "^5.4.10",
"vitest": "^2.1.3"
},
"dependencies": {
"@babel/core": "^7.26.0",
"@babel/parser": "^7.26.2",
"@babel/traverse": "^7.25.9",
"@babel/types": "^7.26.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-select": "^1.2.2",
"beautify": "^0.0.8",
"chalk": "^5.3.0",
"clsx": "^2.0.0",
"date-fns": "^4.1.0",
"es-module-lexer": "^1.4.1",
"framer-motion": "^11.11.10",
"react-d3-tree": "^3.6.2",
"react-diff-viewer-continued": "^3.3.1",
"react-hotkeys-hook": "^4.5.0",
"react-router": "^7.0.0-pre.1",
"tailwind-merge": "^1.14.0"
"react-router": "7.0.0-pre.2",
"react-tooltip": "^5.28.0"
}
}
}
1 change: 1 addition & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
export { EmbeddedDevTools } from "./client/EmbeddedDevTools.js"
export { withViteDevTools } from "./client/init/root.js"
export { defineClientConfig } from "./client/init/root.js"
export { withClientLoaderWrapper, withClientActionWrapper } from "./client/hof.js"
17 changes: 17 additions & 0 deletions src/client/components/icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@ export const Icon = ({ name, testId, className, size = "sm", ...props }: IconPro
<path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3" />
<path d="M12 12V8" />
</symbol>
<symbol
id="Network"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m13.11 7.664 1.78 2.672" />
<path d="m14.162 12.788-3.324 1.424" />
<path d="m20 4-6.06 1.515" />
<path d="M3 3v16a2 2 0 0 0 2 2h16" />
<circle cx="12" cy="6" r="2" />
<circle cx="16" cy="12" r="2" />
<circle cx="9" cy="15" r="2" />
</symbol>
<symbol
id="X"
viewBox="0 0 24 24"
Expand Down
7 changes: 5 additions & 2 deletions src/client/components/jsonRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { useSettingsContext } from "../context/useRDTContext.js"

interface JsonRendererProps {
data: string | Record<string, unknown>
expansionLevel?: number
}

const isPromise = (value: any): value is Promise<any> => {
return value && typeof value.then === "function"
}

const JsonRenderer = ({ data }: JsonRendererProps) => {
const JsonRenderer = ({ data, expansionLevel }: JsonRendererProps) => {
const { settings } = useSettingsContext()
const ref = useRef(true)
useEffect(() => {
Expand Down Expand Up @@ -57,7 +58,9 @@ const JsonRenderer = ({ data }: JsonRendererProps) => {
return <div className="rdt-max-w-xs rdt-text-green-600">{json}</div>
}

return <JsonView highlightUpdates style={customTheme} collapsed={settings.expansionLevel} value={json} />
return (
<JsonView highlightUpdates style={customTheme} collapsed={expansionLevel ?? settings.expansionLevel} value={json} />
)
}

export { JsonRenderer }
111 changes: 111 additions & 0 deletions src/client/components/network-tracer/NetworkBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { animate, motion, useMotionValue } from "framer-motion"
import type React from "react"
import { useEffect } from "react"
import type { NetworkRequest } from "./types"

interface NetworkBarProps {
request: NetworkRequest
index: number
minTime: number
pixelsPerMs: number
barHeight: number
barPadding: number
now: number
onClick: (e: React.MouseEvent, request: NetworkRequest, order: number) => void
isActive: boolean
}

const COLORS = {
loader: "#4ade80",
"client-loader": "#60a5fa",
action: "#f59e0b",
"client-action": "#ef4444",
pending: "#94a3b8",
error: "#dc2626",
}

export const NetworkBar: React.FC<NetworkBarProps> = ({
request,
index,
minTime,
pixelsPerMs,
barHeight,
barPadding,
now,
onClick,
isActive,
}) => {
const startX = (request.startTime - minTime) * pixelsPerMs
const currentEndTime = request.endTime || now
const duration = currentEndTime - request.startTime
const y = index * (barHeight + barPadding) + 24
const state = request.endTime ? "finished" : "pending"

const color = state === "pending" ? COLORS.pending : COLORS[request.type as keyof typeof COLORS]

const barWidth = useMotionValue(2)

useEffect(() => {
const updateWidth = () => {
if (request.endTime) {
animate(barWidth, Math.max(2, (request.endTime - request.startTime) * pixelsPerMs), {
duration: 0.3,
ease: "easeOut",
})
} else if (isActive) {
barWidth.set(Math.max(2, (now - request.startTime) * pixelsPerMs))
requestAnimationFrame(updateWidth)
}
}

if (isActive) {
requestAnimationFrame(updateWidth)
}

if (!isActive) {
barWidth.stop()
}

return () => {
barWidth.stop()
}
}, [request.endTime, request.startTime, pixelsPerMs, now, barWidth, isActive])

return (
<motion.div
style={{
position: "absolute",
top: y,
height: barHeight,
backgroundColor: color,
borderRadius: "2px",
width: barWidth,
minWidth: "2px",
x: startX,
}}
transition={{
x: { duration: 0.3, ease: "easeOut" },
}}
className="relative overflow-hidden group cursor-pointer hover:brightness-110"
onClick={(e) => onClick(e, request, index)}
>
{request.state === "pending" && isActive && (
<motion.div
className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent opacity-20"
animate={{ x: ["-100%", "100%"] }}
transition={{
repeat: Number.POSITIVE_INFINITY,
duration: 1.5,
ease: "linear",
}}
/>
)}

<div className="absolute left-full top-1/2 -translate-y-1/2 ml-2 opacity-0 group-hover:opacity-100 transition-opacity bg-gray-900 px-2 py-1 rounded text-xs whitespace-nowrap pointer-events-none z-10">
{request.method} {request.url}
<br />
{request.endTime ? `Duration: ${duration.toFixed(0)}ms` : `Elapsed: ${duration.toFixed(0)}ms...`}
</div>
</motion.div>
)
}
42 changes: 42 additions & 0 deletions src/client/components/network-tracer/NetworkPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useEffect, useState } from "react"
import { useRequestContext } from "../../context/requests/request-context"

import NetworkWaterfall from "./NetworkWaterfall"

function NetworkPanel() {
const { requests } = useRequestContext()

const [containerWidth, setContainerWidth] = useState(800)

//console.log(req)
// Simulate network requests for demo

// Update container width on resize
useEffect(() => {
const updateWidth = () => {
const container = document.querySelector(".network-container")
if (container) {
setContainerWidth(container.clientWidth)
}
}

window.addEventListener("resize", updateWidth)
updateWidth()

return () => window.removeEventListener("resize", updateWidth)
}, [])

return (
<div className=" text-gray-100">
<div className="mx-auto p-1">
<div className="bg-gray-800 rounded-lg shadow-xl overflow-hidden">
<div className="border-t border-gray-700 p-4 network-container">
<NetworkWaterfall requests={requests} width={containerWidth - 32} />
</div>
</div>
</div>
</div>
)
}

export default NetworkPanel
Loading

0 comments on commit 8cefe29

Please sign in to comment.