Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions packages/core/src/canvas/dashboardsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,23 @@ function useChannelRows(kind: "dashboard" | "task") {
return { rows, loadMore, loading, done };
}

// Resolve the channel's display name (its folder's last path segment) at runtime
// from the baked-in id, so a renamed channel still greets correctly. Empty until
// resolved, so the header avoids a flash of a bare "#".
function useChannelName(): string {
const [name, setName] = useState("");
useEffect(() => {
let alive = true;
void resolveChannelPath().then((path) => {
if (alive && path) setName(lastSegment(path));
});
Comment on lines +443 to +445

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 useChannelName uses void promise.then(...) without a .catch(), so if ph.query throws (e.g., the system table isn't yet available), a silent unhandled promise rejection fires. useChannelRows — the existing peer hook that calls the same resolveChannelPath — wraps the entire async block in a try/catch. The missing guard is inconsistent and can emit noise or trigger unhandledrejection listeners in the sandbox.

Suggested change
void resolveChannelPath().then((path) => {
if (alive && path) setName(lastSegment(path));
});
void resolveChannelPath().then((path) => {
if (alive && path) setName(lastSegment(path));
}).catch(() => {
// ph.query unavailable; name stays empty, showing the fallback.
});

return () => {
alive = false;
};
}, []);
return name;
}
Comment on lines +439 to +451

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Redundant channel-path query on load

useChannelName issues its own resolveChannelPath() call independently of useChannelRows, so on page load the canvas fires three separate SELECT path FROM system.file_system WHERE id = ... queries: one from useChannelName, one from CanvasesSection, and one from TasksSection. Since useChannelRows already resolves the path and holds it in a pathRef, a shared singleton resolver (e.g., a module-level let resolvedPath: Promise<string> | null) would collapse these into a single round-trip.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!


// A fixed-height, scrollable section card. A sentinel at the bottom (observed
// against THIS box, not the page) fires onLoadMore as the user scrolls near the
// end. Styled to match the PostHog Code app: greenish-gray neutrals, soft
Expand Down Expand Up @@ -710,15 +727,44 @@ const STYLE_TEXT =
"*::-webkit-scrollbar-thumb{background:var(--scroll-thumb);border-radius:8px;border:2px solid transparent;background-clip:padding-box}" +
"*::-webkit-scrollbar-thumb:hover{background:var(--scroll-thumb-hover);background-clip:padding-box}";

function WelcomeHeader() {
const name = useChannelName();
return (
<div style={{ width: "100%", maxWidth: 1200, textAlign: "center" }}>
<h1
style={{
margin: "0 0 12px",
fontSize: 30,
fontWeight: 700,
letterSpacing: "-0.01em",
color: "var(--title)",
}}
>
{name ? "Welcome to #" + name + "." : "Welcome to your channel."}
</h1>
<p style={{ margin: "0 auto", maxWidth: 620, fontSize: 15, lineHeight: 1.55 }}>
This is your home for anything related to this channel. Create dashboards
& apps with Canvases. Put agents to work for you with Tasks.
</p>
<p style={{ margin: "8px auto 0", maxWidth: 620, fontSize: 13, color: "var(--meta)" }}>
This page is a canvas itself — just click edit to tell the agent what you
want your channel homepage to show.
</p>
</div>
);
}

export default function ChannelHome() {
return (
<div
style={{
minHeight: "100vh",
boxSizing: "border-box",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
gap: 36,
padding: 40,
background:
"linear-gradient(180deg, var(--bg-from) 0%, var(--bg-to) 100%)",
Expand All @@ -728,6 +774,7 @@ export default function ChannelHome() {
}}
>
<style>{STYLE_TEXT}</style>
<WelcomeHeader />
<div
style={{
display: "flex",
Expand Down
Loading