feat(bluebird): open channel CONTEXT.md from new-task chip#2822
Conversation
The "Using: #<channel> CONTEXT.md" chip on a channel's new-task composer could previously only be dismissed. Make its icon+label clickable to open a right-side panel with the CONTEXT.md contents, mirroring the post-submit context tab, while keeping the × dismiss intact. - analytics-events: add "view_context" ChannelActionType - TaskInput: optional onContextChipClick prop turns the chip label into a button (other callers unaffected) - ChannelContextPanel: new read-only markdown panel with header + close - WebsiteNewTask: wire the chip to a ResizableSidebar panel + track view_context Generated-By: PostHog Code Task-Id: 5ab05b76-423a-4bf0-a7f4-4efc5253b157
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
There was a problem hiding this comment.
Purely additive UI feature — new optional prop on TaskInput (fully backward-compatible), new side-panel component with tests, and a new analytics event type. No production-risk patterns: no data-model changes, no API contract breaks, no forbidden imports, and all business logic stays out of stores and components. Zero reviews is acceptable here given the additive, well-tested, self-contained nature of the change.
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
packages/ui/src/features/canvas/components/WebsiteNewTask.tsx:40-47
`view_context` tracks on every toggle, so closing the panel fires the event a second time. Each open→close→open cycle inflates the metric by 2×. The fix is to move the `track` call inside the state updater where the previous value is available, firing only when transitioning from closed to open.
```suggestion
const handleContextChipClick = useCallback(() => {
setContextPanelOpen((open) => {
if (!open) {
track(ANALYTICS_EVENTS.CHANNEL_ACTION, {
action_type: "view_context",
surface: "new_task",
channel_id: channelId,
});
}
return !open;
});
}, [channelId]);
```
### Issue 2 of 2
packages/ui/src/features/canvas/components/ChannelContextPanel.test.tsx:34-50
The two title-rendering cases test the same rendering property under different `channelName` inputs and are a natural fit for `it.each`, which is the preferred parameterised style in this codebase.
```suggestion
it.each([
{
channelName: "project-bluebird",
expectedTitle: "#project-bluebird CONTEXT.md",
},
{ channelName: undefined, expectedTitle: "CONTEXT.md" },
])(
"renders title '$expectedTitle' for channelName=$channelName",
({ channelName, expectedTitle }) => {
render(
<Theme>
<ChannelContextPanel
channelName={channelName}
body="# Heading\n\nSome **context** body."
onClose={vi.fn()}
/>
</Theme>,
);
expect(screen.getByText(expectedTitle)).toBeInTheDocument();
},
);
```
Reviews (1): Last reviewed commit: "feat(bluebird): open channel CONTEXT.md ..." | Re-trigger Greptile |
| const handleContextChipClick = useCallback(() => { | ||
| setContextPanelOpen((open) => !open); | ||
| track(ANALYTICS_EVENTS.CHANNEL_ACTION, { | ||
| action_type: "view_context", | ||
| surface: "new_task", | ||
| channel_id: channelId, | ||
| }); | ||
| }, [channelId]); |
There was a problem hiding this comment.
view_context tracks on every toggle, so closing the panel fires the event a second time. Each open→close→open cycle inflates the metric by 2×. The fix is to move the track call inside the state updater where the previous value is available, firing only when transitioning from closed to open.
| const handleContextChipClick = useCallback(() => { | |
| setContextPanelOpen((open) => !open); | |
| track(ANALYTICS_EVENTS.CHANNEL_ACTION, { | |
| action_type: "view_context", | |
| surface: "new_task", | |
| channel_id: channelId, | |
| }); | |
| }, [channelId]); | |
| const handleContextChipClick = useCallback(() => { | |
| setContextPanelOpen((open) => { | |
| if (!open) { | |
| track(ANALYTICS_EVENTS.CHANNEL_ACTION, { | |
| action_type: "view_context", | |
| surface: "new_task", | |
| channel_id: channelId, | |
| }); | |
| } | |
| return !open; | |
| }); | |
| }, [channelId]); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/canvas/components/WebsiteNewTask.tsx
Line: 40-47
Comment:
`view_context` tracks on every toggle, so closing the panel fires the event a second time. Each open→close→open cycle inflates the metric by 2×. The fix is to move the `track` call inside the state updater where the previous value is available, firing only when transitioning from closed to open.
```suggestion
const handleContextChipClick = useCallback(() => {
setContextPanelOpen((open) => {
if (!open) {
track(ANALYTICS_EVENTS.CHANNEL_ACTION, {
action_type: "view_context",
surface: "new_task",
channel_id: channelId,
});
}
return !open;
});
}, [channelId]);
```
How can I resolve this? If you propose a fix, please make it concise.| it("renders the channel-qualified CONTEXT.md title and body", () => { | ||
| renderPanel(); | ||
| expect( | ||
| screen.getByText("#project-bluebird CONTEXT.md"), | ||
| ).toBeInTheDocument(); | ||
| expect(screen.getByText("Heading")).toBeInTheDocument(); | ||
| expect(screen.getByText("context")).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it("omits the channel prefix when no name is given", () => { | ||
| render( | ||
| <Theme> | ||
| <ChannelContextPanel body="body" onClose={vi.fn()} /> | ||
| </Theme>, | ||
| ); | ||
| expect(screen.getByText("CONTEXT.md")).toBeInTheDocument(); | ||
| }); |
There was a problem hiding this comment.
The two title-rendering cases test the same rendering property under different
channelName inputs and are a natural fit for it.each, which is the preferred parameterised style in this codebase.
| it("renders the channel-qualified CONTEXT.md title and body", () => { | |
| renderPanel(); | |
| expect( | |
| screen.getByText("#project-bluebird CONTEXT.md"), | |
| ).toBeInTheDocument(); | |
| expect(screen.getByText("Heading")).toBeInTheDocument(); | |
| expect(screen.getByText("context")).toBeInTheDocument(); | |
| }); | |
| it("omits the channel prefix when no name is given", () => { | |
| render( | |
| <Theme> | |
| <ChannelContextPanel body="body" onClose={vi.fn()} /> | |
| </Theme>, | |
| ); | |
| expect(screen.getByText("CONTEXT.md")).toBeInTheDocument(); | |
| }); | |
| it.each([ | |
| { | |
| channelName: "project-bluebird", | |
| expectedTitle: "#project-bluebird CONTEXT.md", | |
| }, | |
| { channelName: undefined, expectedTitle: "CONTEXT.md" }, | |
| ])( | |
| "renders title '$expectedTitle' for channelName=$channelName", | |
| ({ channelName, expectedTitle }) => { | |
| render( | |
| <Theme> | |
| <ChannelContextPanel | |
| channelName={channelName} | |
| body="# Heading\n\nSome **context** body." | |
| onClose={vi.fn()} | |
| /> | |
| </Theme>, | |
| ); | |
| expect(screen.getByText(expectedTitle)).toBeInTheDocument(); | |
| }, | |
| ); |
Context Used: Do not attempt to comment on incorrect alphabetica... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/canvas/components/ChannelContextPanel.test.tsx
Line: 34-50
Comment:
The two title-rendering cases test the same rendering property under different `channelName` inputs and are a natural fit for `it.each`, which is the preferred parameterised style in this codebase.
```suggestion
it.each([
{
channelName: "project-bluebird",
expectedTitle: "#project-bluebird CONTEXT.md",
},
{ channelName: undefined, expectedTitle: "CONTEXT.md" },
])(
"renders title '$expectedTitle' for channelName=$channelName",
({ channelName, expectedTitle }) => {
render(
<Theme>
<ChannelContextPanel
channelName={channelName}
body="# Heading\n\nSome **context** body."
onClose={vi.fn()}
/>
</Theme>,
);
expect(screen.getByText(expectedTitle)).toBeInTheDocument();
},
);
```
**Context Used:** Do not attempt to comment on incorrect alphabetica... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))
How can I resolve this? If you propose a fix, please make it concise.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!
Address PR review: - view_context no longer fires when closing the panel (only on closed→open), so toggling doesn't inflate the metric. Test now asserts the second click closes without re-tracking. - ChannelContextPanel title cases use it.each per repo convention. Generated-By: PostHog Code Task-Id: 5ab05b76-423a-4bf0-a7f4-4efc5253b157
New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.
There was a problem hiding this comment.
Purely additive UI feature with good test coverage. Both bot concerns (analytics double-tracking and it.each style) were already addressed before this review — the current code guards tracking behind the open-transition check and uses the parameterized test form. No showstoppers found.
Problem
In a channel's new-task composer (project-bluebird), the
Using: #<channel> CONTEXT.mdchip could only be dismissed (×) — there was no way to see what the CONTEXT.md actually contains before submitting. After submit you can open the context tab to read it; this brings the same affordance to the composer.Why: users wanted to review the channel context that will be attached to a task before sending it, not only afterward.
Changes
TaskInput: new optionalonContextChipClickprop turns the chip's icon+label into a button (tooltip "View this context"). The × dismiss is unchanged, and the otherTaskInputcallers are unaffected.ChannelContextPanel(new): read-only markdown panel with a header + close button, mirroringChannelContextTab.WebsiteNewTask: wires the chip to a right-sideResizableSidebarpanel; content is mounted only while open, and the chip stays non-interactive when the channel has no CONTEXT.md.view_contextChannelActionType, tracked on chip click.How did you test this?
pnpm --filter @posthog/ui typecheckand@posthog/sharedtypecheck — cleanChannelContextPanel(title/body/no-prefix/close) andWebsiteNewTask(chip → panel opens +view_contexttracked; chip disabled when no context)Not done: manual run of the Electron app.
Automatic notifications
Created with PostHog Code