feat(channels): add "Recent tasks" nav option#3023
Conversation
Add a "Recent tasks" item to the Channels-space nav (below "Files") that opens a cross-channel list of every task, most recent first. Each row shows the task's channel, its last-updated time (human-readable), and the same status icon the sidebar and command palette render (TaskIcon). Gated by project-bluebird via the /website space. Generated-By: PostHog Code Task-Id: 51e058ce-6cca-43fa-b056-95ae0ff5f5b6
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
|
Reviews (1): Last reviewed commit: "feat(channels): add "Recent tasks" nav o..." | Re-trigger Greptile |
| export function RecentTasksView() { | ||
| const { data: tasks } = useTasks(); | ||
| const { channels } = useChannels(); | ||
| const taskChannelMap = useTaskChannelMap(channels); | ||
| const archivedTaskIds = useArchivedTaskIds(); | ||
|
|
||
| useEffect(() => { | ||
| track(ANALYTICS_EVENTS.CHANNEL_ACTION, { | ||
| action_type: "view_recent_tasks", | ||
| surface: "recent_tasks", | ||
| }); | ||
| }, []); | ||
|
|
||
| const rows = useMemo<RecentTaskRow[]>(() => { | ||
| return (tasks ?? []) | ||
| .filter((task) => !archivedTaskIds.has(task.id)) | ||
| .map((task) => ({ | ||
| task, | ||
| channel: taskChannelMap.get(task.id), | ||
| updatedAt: Date.parse(task.updated_at) || 0, | ||
| })) | ||
| .sort((a, b) => b.updatedAt - a.updatedAt); | ||
| }, [tasks, taskChannelMap, archivedTaskIds]); |
There was a problem hiding this comment.
Premature empty state during data load
useTasks() returns undefined while the network request is in flight. Because the component uses tasks ?? [], rows is always an empty array during loading, so "No tasks yet" is shown immediately on every mount before the API responds. The fix is to also destructure isLoading (or isPending) and guard the empty-state branch with it.
Per the codebase rule, conditions for loading vs. empty must be kept distinct to avoid prematurely rendering empty states.
Rule Used: In cases where there are multiple states to handle... (source)
Learned From
PostHog/posthog#32610
There was a problem hiding this comment.
🤖 Agent (PostHog Code) posting on @raquelmsmith's behalf at her request.
Already handled in the current revision: RecentTasksView destructures isLoading from useTasks() and only renders the "No tasks yet" empty state once loading has finished (isLoading ? null : <empty>), so it no longer flashes during the in-flight request.
| .map((task) => ({ | ||
| task, | ||
| channel: taskChannelMap.get(task.id), | ||
| updatedAt: Date.parse(task.updated_at) || 0, | ||
| })) |
There was a problem hiding this comment.
Epoch fallback date shown for unparseable
updated_at
When Date.parse(task.updated_at) returns NaN, the || 0 fallback silently assigns epoch 0 (Jan 1, 1970). formatRelativeTimeLong(0) will then render a very old absolute date in the subtitle row instead of something user-friendly. If updated_at can ever be missing or malformed, a null-style guard (skipping or showing "–") would be less confusing than a 1970 timestamp.
There was a problem hiding this comment.
🤖 Agent (PostHog Code) posting on @raquelmsmith's behalf at her request.
Already handled in the current revision: an unparseable updated_at now maps to updatedAt: null (not epoch 0), the row omits the relative-time segment entirely when it's null, and such rows sort last. No more 1970 dates.
Address code-review feedback on the Recent tasks view: - Don't flash the "No tasks yet" empty state while the task list is still loading (useTasks() returns undefined in flight) — guard it with isLoading. - Omit the relative time when updated_at can't be parsed, instead of showing a misleading epoch (1970) date. - Build the rows in a single filter+map pass before sorting. Generated-By: PostHog Code Task-Id: 51e058ce-6cca-43fa-b056-95ae0ff5f5b6
- Prefix the channel with "#" and keep the channel + last-updated metadata on the left of each row. - Show small clickable icons on the right for artifacts a task produced: canvases it generated (via the dashboard's durable generationTaskId) and the pull request it opened (latest_run.output.pr_url). Clicking a canvas opens it in its channel; clicking the PR opens it in the browser. No PostHog data-model change was needed — both associations already exist. Generated-By: PostHog Code Task-Id: 51e058ce-6cca-43fa-b056-95ae0ff5f5b6
Title now occupies a single line on the left; #channel · time moves to the right edge next to the artifact icons, balancing the row's visual weight. Generated-By: PostHog Code Task-Id: 86f54a5c-8435-47e9-b5e0-d94b6cc286ba
… icons Recent tasks was a route the tab system couldn't represent — tabs are keyed only on canvas/task/channel, so /website/recent-tasks fell through to a "New tab" label and was dropped when switching tabs and back. Add a `routeId` to the tab identity (schema + DB column/migration + nav decision) so a standalone Channels-space route is a real tab: labelled "Recent tasks", deduped, and restored across switches. Also on the recent-tasks rows: move the canvas/PR artifact icons next to the task name and give them colour-coded chips matching the channel artifacts/history rows (canvas = violet, PR = green) so they read as artifacts at a glance. Generated-By: PostHog Code Task-Id: 86f54a5c-8435-47e9-b5e0-d94b6cc286ba
The generated drizzle snapshot had multiline arrays that biome's formatter collapses to single lines, failing `biome ci` (quality check). Reformat to match biome's output. Generated-By: PostHog Code Task-Id: 087e1c07-151d-4eee-9de9-5a63ae6acaa5
Problem
In the Channels (project-bluebird) space, there was no single place to see every task across all channels at a glance. This adds a Recent tasks nav option (below Files) that lists all tasks, most recent first, so you can jump to any task without first navigating into its channel.
Changes
/website/recent-tasksview.TaskIconcomponent the sidebar and command palette use (cloud run states, Slack origin, etc.).view_recent_tasksaction on a newrecent_taskssurface; the nav click reuses the existingnav_clicktracking.Gated by
project-bluebirdsince the whole/websitespace only renders when the flag is on.How did you test this?
pnpm --filter @posthog/ui typecheck— passes (after building upstream package types).pnpm --filter @posthog/shared typecheckandtest time— pass.generate-routesscript (not hand-edited).Automatic notifications
Created with PostHog Code