Repository navigation
Expand file tree
/
Copy pathClientDemoPanel.jsx
More file actions
156 lines (129 loc) · 5.53 KB
/
Copy pathClientDemoPanel.jsx
File metadata and controls
156 lines (129 loc) · 5.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"use client";
import Link from "next/link";
import { useState, useTransition } from "react";
import { Exceptionless, startup } from "../lib/exceptionless-browser.js";
export default function ClientDemoPanel() {
const [status, setStatus] = useState("Ready. Pick any path below to generate client or server telemetry.");
const [pending, startTransition] = useTransition();
async function sendClientLog() {
setStatus("Submitting a structured client log...");
await startup();
await Exceptionless.createLog("nextjs.client", "Client log from the demo page", "info")
.addTags("manual-log")
.setProperty("currentUrl", window.location.href)
.setProperty("timezone", Intl.DateTimeFormat().resolvedOptions().timeZone)
.submit();
setStatus("Client log submitted.");
}
async function sendHandledClientError() {
setStatus("Submitting a handled client error...");
try {
throw new Error("Handled client error from the Exceptionless Next.js demo");
} catch (error) {
await startup();
await Exceptionless.createException(error)
.addTags("handled-error")
.setProperty("handledBy", "ClientDemoPanel.handleTryCatch")
.setProperty("currentUrl", window.location.href)
.submit();
}
setStatus("Handled client error submitted.");
}
function triggerUnhandledRejection() {
setStatus("Triggered an unhandled promise rejection. The browser global handler should capture it.");
Promise.reject(new Error("Unhandled promise rejection from the Exceptionless Next.js demo"));
}
function triggerBoundaryCrash() {
setStatus("Crashing the route boundary...");
startTransition(() => {
throw new Error("Client transition crash from the Exceptionless Next.js demo");
});
}
async function callServerRoute(mode) {
setStatus(mode === "error" ? "Triggering a route handler crash..." : "Submitting a route handler log...");
const response = await fetch("/api/demo", {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
mode,
triggeredFrom: "ClientDemoPanel",
currentUrl: window.location.href,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
})
});
if (!response.ok) {
setStatus(`Route handler error triggered with HTTP ${response.status}. The server onRequestError hook should capture it.`);
return;
}
const payload = await response.json();
setStatus(payload.message);
}
return (
<section className="panel">
<div className="panel-body">
<h2>Try the integration</h2>
<p>
The first four buttons stay in the browser. The next two go through a real Next route handler. The link at the bottom opens a route that throws during
server rendering.
</p>
<div className="button-grid">
<button type="button" onClick={() => void sendClientLog()} disabled={pending}>
<span className="button-label">
<strong>Send client log</strong>
<span>Manual log event with URL and timezone metadata.</span>
</span>
<span className="button-arrow">+</span>
</button>
<button type="button" onClick={() => void sendHandledClientError()} disabled={pending}>
<span className="button-label">
<strong>Send handled client error</strong>
<span>Manual exception capture from a local try/catch block.</span>
</span>
<span className="button-arrow">+</span>
</button>
<button type="button" onClick={triggerUnhandledRejection} disabled={pending}>
<span className="button-label">
<strong>Trigger unhandled rejection</strong>
<span>Exercises the browser global handler installed during startup.</span>
</span>
<span className="button-arrow">!</span>
</button>
<button type="button" onClick={triggerBoundaryCrash} disabled={pending}>
<span className="button-label">
<strong>Crash the route boundary</strong>
<span>Throws inside a transition so `app/error.jsx` catches it.</span>
</span>
<span className="button-arrow">!</span>
</button>
<button type="button" onClick={() => void callServerRoute("log")} disabled={pending}>
<span className="button-label">
<strong>Send server route log</strong>
<span>Hits `/api/demo` and enriches the log with request data.</span>
</span>
<span className="button-arrow">+</span>
</button>
<button type="button" onClick={() => void callServerRoute("error")} disabled={pending}>
<span className="button-label">
<strong>Trigger route handler error</strong>
<span>Throws in `/api/demo` so `instrumentation.js` captures it.</span>
</span>
<span className="button-arrow">!</span>
</button>
<Link href="/server-component-error" prefetch={false}>
<span className="button-label">
<strong>Open the server component error route</strong>
<span>Exercises the App Router render path and `onRequestError`.</span>
</span>
<span className="button-arrow">→</span>
</Link>
</div>
<div className="status">
<strong>Latest status</strong>
<span>{status}</span>
</div>
</div>
</section>
);
}