Skip to content

Commit 885532b

Browse files
committed
feat(obs): create scaffolding for observability spa as example
1 parent 9ff4c11 commit 885532b

File tree

14 files changed

+1148
-0
lines changed

14 files changed

+1148
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>Observability SPA</title>
5+
</head>
6+
<body>
7+
<div id="root"></div>
8+
<script type="module" src="/src/observability/client.tsx"></script>
9+
</body>
10+
</html>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>Observability Example</title>
5+
</head>
6+
<body>
7+
<div id="root"></div>
8+
<script type="module" src="/src/application/client.tsx"></script>
9+
</body>
10+
</html>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"author": "",
3+
"description": "",
4+
"devDependencies": {
5+
"@tailwindcss/vite": "^4.1.5",
6+
"tailwindcss": "^4.1.5"
7+
},
8+
"keywords": [],
9+
"license": "ISC",
10+
"name": "@cloudflare/agents-observability-spa-example",
11+
"private": true,
12+
"scripts": {
13+
"deploy": "vite build && wrangler deploy",
14+
"start": "vite dev"
15+
},
16+
"type": "module",
17+
"version": "0.0.0"
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { createRoot } from "react-dom/client";
2+
import Chat from "./components/Chat";
3+
import "./styles.css";
4+
5+
function App() {
6+
return (
7+
<div className="container">
8+
<div className="col-span-1">
9+
<Chat />
10+
</div>
11+
</div>
12+
);
13+
}
14+
15+
createRoot(document.getElementById("root")!).render(<App />);
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/* Chat Wrapper Styles */
2+
.chat-wrapper {
3+
display: flex;
4+
flex-direction: column;
5+
height: 100%;
6+
padding: 20px;
7+
}
8+
9+
.tab-bar {
10+
display: flex;
11+
gap: 4px;
12+
margin-bottom: 20px;
13+
}
14+
15+
.tab {
16+
padding: 10px 20px;
17+
border: none;
18+
border-radius: 8px;
19+
background-color: #f0f0f0;
20+
color: #666;
21+
cursor: pointer;
22+
transition: all 0.2s ease;
23+
font-size: 14px;
24+
font-weight: 500;
25+
}
26+
27+
.tab:hover {
28+
background-color: #e0e0e0;
29+
color: #333;
30+
}
31+
32+
.tab.active {
33+
background-color: #007bff;
34+
color: white;
35+
}
36+
37+
/* Chat Room Styles */
38+
.chat-container {
39+
display: flex;
40+
flex-direction: column;
41+
height: 80vh;
42+
max-width: 800px;
43+
margin: 0 auto;
44+
padding: 20px;
45+
background-color: #ffffff;
46+
border-radius: 12px;
47+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
48+
width: 100%;
49+
}
50+
51+
.messages-wrapper {
52+
flex: 1;
53+
overflow-y: auto;
54+
padding: 20px;
55+
margin-bottom: 20px;
56+
}
57+
58+
.message {
59+
margin-bottom: 16px;
60+
padding: 12px;
61+
border-radius: 8px;
62+
background-color: #f5f5f5;
63+
color: #333333;
64+
}
65+
66+
.message-content {
67+
margin-top: 8px;
68+
line-height: 1.5;
69+
white-space: pre-wrap;
70+
}
71+
72+
.chat-input {
73+
width: 100%;
74+
padding: 12px;
75+
border: 2px solid #e0e0e0;
76+
border-radius: 8px;
77+
font-size: 16px;
78+
background-color: #ffffff;
79+
color: #333333;
80+
transition: border-color 0.2s ease;
81+
box-sizing: border-box;
82+
}
83+
84+
.chat-input:focus {
85+
outline: none;
86+
border-color: #007bff;
87+
}
88+
89+
.controls-container {
90+
display: flex;
91+
justify-content: flex-end;
92+
gap: 12px;
93+
padding: 12px;
94+
}
95+
96+
.clear-history {
97+
padding: 8px 16px;
98+
border: none;
99+
border-radius: 8px;
100+
background-color: #f0f0f0;
101+
color: #333333;
102+
cursor: pointer;
103+
transition: background-color 0.2s ease;
104+
}
105+
106+
.clear-history:hover {
107+
background-color: #e0e0e0;
108+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type { Message } from "@ai-sdk/react";
2+
import "./Chat.css";
3+
import { useAgentChat } from "agents/ai-react";
4+
import { useAgent } from "agents/react";
5+
import { useCallback, useEffect, useRef } from "react";
6+
7+
export default function Chat() {
8+
const messagesEndRef = useRef<HTMLDivElement>(null);
9+
10+
const scrollToBottom = useCallback(() => {
11+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
12+
}, []);
13+
14+
// Scroll to bottom on mount
15+
useEffect(() => {
16+
scrollToBottom();
17+
}, [scrollToBottom]);
18+
19+
const agent = useAgent({
20+
agent: "TestingAgent",
21+
name: "chat",
22+
});
23+
24+
const { messages, input, handleInputChange, handleSubmit } = useAgentChat({
25+
agent,
26+
maxSteps: 5,
27+
});
28+
29+
// Scroll to bottom when messages change
30+
useEffect(() => {
31+
messages.length > 0 && scrollToBottom();
32+
}, [messages, scrollToBottom]);
33+
34+
return (
35+
<div className="chat-wrapper">
36+
<div className="chat-container">
37+
<div className="messages-wrapper">
38+
{messages?.map((m: Message) => (
39+
<div key={m.id} className="message">
40+
<strong>{`${m.role}: `}</strong>
41+
{m.parts?.map((part, i) => {
42+
switch (part.type) {
43+
case "text":
44+
return (
45+
// biome-ignore lint/suspicious/noArrayIndexKey: vibes
46+
<div key={i} className="message-content">
47+
{part.text}
48+
</div>
49+
);
50+
default:
51+
return null;
52+
}
53+
})}
54+
<br />
55+
</div>
56+
))}
57+
<div ref={messagesEndRef} />
58+
</div>
59+
60+
<form onSubmit={handleSubmit}>
61+
<input
62+
className="chat-input"
63+
value={input}
64+
placeholder="Say something..."
65+
onChange={handleInputChange}
66+
/>
67+
</form>
68+
</div>
69+
</div>
70+
);
71+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* Global styles */
2+
body {
3+
margin: 0;
4+
font-family:
5+
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
6+
Arial, sans-serif;
7+
background-color: #f5f5f5;
8+
}
9+
10+
/* Global container style */
11+
.container {
12+
max-width: 800px;
13+
margin: 40px auto;
14+
padding: 0 20px;
15+
}
16+
17+
/* Global toast notifications */
18+
.toasts-container {
19+
position: fixed;
20+
top: 20px;
21+
right: 20px;
22+
z-index: 1000;
23+
display: flex;
24+
flex-direction: column;
25+
gap: 10px;
26+
}
27+
28+
.toast {
29+
min-width: 200px;
30+
padding: 12px 24px;
31+
border-radius: 6px;
32+
color: white;
33+
font-size: 14px;
34+
font-weight: 500;
35+
animation: slideIn 0.3s ease-out forwards;
36+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
37+
}
38+
39+
.toast-success {
40+
background-color: #28a745;
41+
}
42+
43+
.toast-error {
44+
background-color: #dc3545;
45+
}
46+
47+
.toast-info {
48+
background-color: #17a2b8;
49+
}
50+
51+
@keyframes slideIn {
52+
from {
53+
transform: translateX(100%);
54+
opacity: 0;
55+
}
56+
to {
57+
transform: translateX(0);
58+
opacity: 1;
59+
}
60+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { createRoot } from "react-dom/client";
2+
import "./styles.css";
3+
4+
function App() {
5+
return (
6+
<div className="flex items-center justify-center h-screen">
7+
<h1 className="text-4xl font-bold mb-4">Observability</h1>
8+
</div>
9+
);
10+
}
11+
12+
createRoot(document.getElementById("root")!).render(<App />);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "tailwindcss";

0 commit comments

Comments
 (0)