Skip to content

feat: display the number of idle tasks in the navbar #19471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 22, 2025
Merged

Conversation

BrunoQuaresma
Copy link
Collaborator

@BrunoQuaresma BrunoQuaresma commented Aug 21, 2025

Depends on: #19377

Closes #19323

Screenshot:

Screenshot 2025-08-21 at 11 52 21

Screen recording:

Screen.Recording.2025-08-21.at.11.52.43.mov

Summary by CodeRabbit

  • New Features

    • Added a Tasks navigation item showing a badge with the number of idle tasks and a tooltip: “You have X tasks waiting for input.”
  • Improvements

    • Fetches per-user tasks with periodic refresh for up-to-date counts.
    • Updated active styling for the Tasks link for clearer navigation state.
    • User menu now always appears on medium+ screens.
  • Tests

    • Expanded Storybook with preloaded, user-filtered task scenarios to showcase idle/task states.

@BrunoQuaresma BrunoQuaresma requested a review from a team August 21, 2025 15:05
@BrunoQuaresma BrunoQuaresma self-assigned this Aug 21, 2025
@BrunoQuaresma BrunoQuaresma requested review from Kira-Pilot and removed request for a team August 21, 2025 15:05
@BrunoQuaresma BrunoQuaresma requested a review from aslilac as a code owner August 21, 2025 15:05
@BrunoQuaresma BrunoQuaresma requested review from a team and removed request for Kira-Pilot August 21, 2025 15:05
const { data: idleTasks } = useQuery({
queryKey: ["tasks", filter],
queryFn: () => data.fetchTasks(filter),
refetchInterval: 10_000,
Copy link
Member

Choose a reason for hiding this comment

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

Can we use a longer fetch interval and conditionally refetch if an action to create a workspace / task was performed in the last fetch interval?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Can we use a longer fetch interval

Yeap! Wdyt about one minute?

Conditionally refetch if an action to create a workspace / task was performed in the last fetch interval?

Hm... I think so, but it looks complex. IMO, we could increase the refetch time and see if it is necessary to optimize it to avoid adding unnecessary complexity. Thoughts?

Copy link
Member

@johnstcn johnstcn Aug 21, 2025

Choose a reason for hiding this comment

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

Yeah, let's go with 30 60s initially.

Comment on lines 109 to 120
data: [
{
prompt: "Task 1",
workspace: {
...MockWorkspace,
latest_app_status: {
...MockWorkspaceAppStatus,
state: "idle",
},
},
},
],
Copy link
Member

Choose a reason for hiding this comment

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

suggest including additional non-idle tasks in the input

Comment on lines 215 to 221
const search =
idleTasks && idleTasks.length > 0
? new URLSearchParams({
username: user.username,
tab: "waiting-for-input",
}).toString()
: undefined;
Copy link
Member

@aslilac aslilac Aug 21, 2025

Choose a reason for hiding this comment

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

I don't think we should change the url of this button just based on whether you have an idle task or not. if clicking the badge specifically took you to the page with this search set I would be fine with that, but the behavior of the whole button changing back and forth is confusing to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Makes sense 👍

enabled: canSeeTasks,
refetchOnWindowFocus: true,
select: (data) =>
data.filter((task) => task.workspace.latest_app_status?.state === "idle"),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
data.filter((task) => task.workspace.latest_app_status?.state === "idle"),
data.filter((task) => task.workspace.latest_app_status?.state === "idle").length,

I think you could just select the length yeah? and maybe even set initialData to 0 so you don't have to worry about loading states as much

<NavLink
to={{ pathname: "/tasks", search }}
className={({ isActive }) => {
return cn(linkStyles.default, isActive ? linkStyles.active : "");
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return cn(linkStyles.default, isActive ? linkStyles.active : "");
return cn(linkStyles.default, isActive && linkStyles.active);

no need to hand it an empty string, it's smart enough to filter

Copy link

coderabbitai bot commented Aug 22, 2025

Walkthrough

Adds a Tasks nav item that fetches user-scoped tasks via the experimental API, counts “idle” tasks, and displays a badge with a tooltip. Updates NavbarView to require a user prop and adjusts rendering. Storybook now preloads filter-scoped task data and adds an IdleTasks story.

Changes

Cohort / File(s) Summary
Navbar tasks integration
site/src/modules/dashboard/Navbar/NavbarView.tsx
Adds TasksNavItem component; uses react-query to fetch per-user tasks (["tasks", filter]) with refetch interval and initialData; counts tasks with state === "idle" and shows Badge + Tooltip when >0; replaces static Tasks link with component; changes NavLink active-style; makes NavbarViewProps.user required; always renders UserDropdown for md+; adds imports (Badge, Tooltip, useQuery, experimental API).
Storybook tasks data & story
site/src/modules/dashboard/Navbar/NavbarView.stories.tsx
Imports MockWorkspace and MockWorkspaceAppStatus; defines tasksFilter keyed by MockUserOwner.username; sets meta queries for ["tasks", tasksFilter] with initial empty data; adds IdleTasks story preloading three tasks (one idle, two non-idle) and exports it.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant NV as NavbarView
  participant TNI as TasksNavItem
  participant RQ as ReactQuery Cache
  participant API as experimental.getTasks(filter)

  U->>NV: Mount navbar with user
  NV->>TNI: Render TasksNavItem(user)
  TNI->>RQ: useQuery(["tasks", userFilter], fetcher, { refetchInterval, initialData })
  alt Cache hit
    RQ-->>TNI: Return cached tasks
  else Cache miss
    RQ->>API: Fetch tasks for user
    API-->>RQ: Tasks[]
    RQ-->>TNI: Store + return
  end
  TNI->>TNI: Compute idleCount = tasks.filter(s=="idle").length
  alt idleCount > 0
    TNI-->>U: Render Tasks link with Badge(idleCount) + Tooltip
  else
    TNI-->>U: Render Tasks link without Badge
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Assessment against linked issues

Objective Addressed Explanation
Display idle task count in navbar [#19323]

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Make NavbarViewProps.user required (site/src/modules/dashboard/Navbar/NavbarView.tsx) Prop contract change not specified in #19323 and affects consumers beyond the idle count feature.
Always render UserDropdown for md+ viewports (site/src/modules/dashboard/Navbar/NavbarView.tsx) UserDropdown visibility change is UI behavior unrelated to showing idle task count.
NavLink active-state styling refactor for Tasks (site/src/modules/dashboard/Navbar/NavbarView.tsx) Styling approach change is visual/tangential and not required by #19323.

"I twitch my ears at badges bright,
Three idle tasks await tonight,
A carrot ping and tooltip light,
I hop to fix them — swift delight.
Cached queries hum; the navbar sings. 🥕🐇"

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a0995bf and cbef909.

📒 Files selected for processing (1)
  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test-e2e
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bq/19323

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@BrunoQuaresma BrunoQuaresma requested a review from aslilac August 22, 2025 14:30
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
site/src/modules/dashboard/Navbar/NavbarView.tsx (1)

162-162: Simplified cn usage is preferred.

Returning cn(linkStyles.default, { [linkStyles.active]: isActive }) is cleaner and matches prior feedback.

Also applies to: 170-170

🧹 Nitpick comments (1)
site/src/modules/dashboard/Navbar/NavbarView.tsx (1)

211-236: Minor a11y improvement for the link’s accessible name.

Currently the link’s accessible name will be “Tasks 3”; the badge’s aria-label does not affect the parent NavLink. Consider giving the NavLink a more descriptive aria-label when there are idle tasks.

Apply this diff:

-    <NavLink
-      to="/tasks"
-      className={({ isActive }) => {
-        return cn(linkStyles.default, { [linkStyles.active]: isActive });
-      }}
-    >
+    <NavLink
+      to="/tasks"
+      aria-label={idleCount > 0 ? `Tasks — ${idleTasksLabel(idleCount)}` : "Tasks"}
+      className={({ isActive }) =>
+        cn(linkStyles.default, { [linkStyles.active]: isActive })
+      }
+    >
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 427b23f and a0995bf.

📒 Files selected for processing (2)
  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx (2 hunks)
  • site/src/modules/dashboard/Navbar/NavbarView.tsx (6 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
site/**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

All user-facing frontend code is developed in TypeScript using React and lives in the site/ directory.

Files:

  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx
  • site/src/modules/dashboard/Navbar/NavbarView.tsx
site/src/**/*.tsx

📄 CodeRabbit inference engine (site/CLAUDE.md)

site/src/**/*.tsx: MUI components are deprecated - migrate away from these when encountered
Use shadcn/ui components first - check site/src/components for existing implementations
Emotion CSS is deprecated. Use Tailwind CSS instead.
Responsive design - use Tailwind's responsive prefixes (sm:, md:, lg:, xl:)
Do not use dark: prefix for dark mode
Group related Tailwind classes
Prefer Tailwind utilities over custom CSS when possible
Use Tailwind classes for all new styling
Replace Emotion css prop with Tailwind classes
Leverage custom color tokens: content-primary, surface-secondary, etc.
Use className with clsx for conditional styling
Don’t call component functions directly; render them via JSX. This keeps Hook rules intact and lets React optimize reconciliation.
After calling a setter you’ll still read the previous state during the same event; updates are queued and batched.
Use functional updates (setX(prev ⇒ …)) whenever next state depends on previous state.
Pass a function to useState(initialFn) for lazy initialization—it runs only on the first render.
If the next state is Object.is-equal to the current one, React skips the re-render.
An Effect takes a setup function and optional cleanup; React runs setup after commit, cleanup before the next setup or on unmount.
The dependency array must list every reactive value referenced inside the Effect, and its length must stay constant.
Effects run only on the client, never during server rendering.
Use Effects solely to synchronize with external systems; if you’re not “escaping React,” you probably don’t need one.
Every sibling element in a list needs a stable, unique key prop. Never use array indexes or Math.random(); prefer data-driven IDs.
Keys aren’t passed to children and must not change between renders; if you return multiple nodes per item, use
useRef stores a mutable .current without causing re-renders.
Avoid reading or mutating refs during render; access them in event handlers or Effects ...

Files:

  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx
  • site/src/modules/dashboard/Navbar/NavbarView.tsx
site/src/modules/**/*

📄 CodeRabbit inference engine (site/CLAUDE.md)

The modules folder should contain components with business logic specific to the codebase

Files:

  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx
  • site/src/modules/dashboard/Navbar/NavbarView.tsx
site/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (site/CLAUDE.md)

site/src/**/*.{ts,tsx}: Use ES modules (import/export) syntax, not CommonJS (require)
Destructure imports when possible (eg. import { foo } from 'bar')
Prefer for...of over forEach for iteration
Components and custom Hooks must be pure and idempotent—same inputs → same output; move side-effects to event handlers or Effects.
Never mutate props, state, or values returned by Hooks. Always create new objects or use the setter from useState.
Only call Hooks at the top level of a function component or another custom Hook—never in loops, conditions, nested functions, or try / catch.
Only call Hooks from React functions. Regular JS functions, classes, event handlers, useMemo, etc. are off-limits.
Never pass Hooks around as values or mutate them dynamically. Keep Hook usage static and local to each component.
Don’t call Hooks (including useRef) inside loops, conditions, or map(). Extract a child component instead.

Files:

  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx
  • site/src/modules/dashboard/Navbar/NavbarView.tsx
**/*.{go,sql,ts,tsx,js,jsx,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Ensure files end with a newline to avoid missing newlines.

Files:

  • site/src/modules/dashboard/Navbar/NavbarView.stories.tsx
  • site/src/modules/dashboard/Navbar/NavbarView.tsx
🧬 Code graph analysis (2)
site/src/modules/dashboard/Navbar/NavbarView.stories.tsx (2)
site/src/testHelpers/entities.ts (3)
  • MockUserOwner (487-500)
  • MockWorkspace (1392-1428)
  • MockWorkspaceAppStatus (1006-1018)
site/src/modules/dashboard/Navbar/NavbarView.tsx (1)
  • NavbarView (46-145)
site/src/modules/dashboard/Navbar/NavbarView.tsx (6)
site/src/api/typesGenerated.ts (1)
  • User (3362-3365)
site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.tsx (1)
  • UserDropdown (19-58)
site/src/hooks/useEmbeddedMetadata.ts (1)
  • useEmbeddedMetadata (245-247)
site/src/api/api.ts (1)
  • API (2818-2818)
site/src/components/Tooltip/Tooltip.tsx (3)
  • TooltipProvider (9-9)
  • TooltipTrigger (13-13)
  • TooltipContent (15-42)
site/src/components/Badge/Badge.tsx (1)
  • Badge (65-83)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test-e2e
  • GitHub Check: chromatic
  • GitHub Check: lint
  • GitHub Check: gen
🔇 Additional comments (7)
site/src/modules/dashboard/Navbar/NavbarView.tsx (6)

3-12: Using shadcn/ui primitives for Badge/Tooltip looks good.

Imports align with our guidelines (no MUI, Tailwind-based components). Nothing to change here.


18-18: Prop type tightened: user is now required.

Making NavbarViewProps.user and NavItemsProps.user non-nullable is appropriate and simplifies downstream logic. Be sure all call sites are updated (stories are).

Also applies to: 28-28, 149-149


71-71: Passing user to NavItems is correct.

Matches the new non-nullable contract and avoids prop drilling via context.


120-127: Always rendering UserDropdown on md+ improves consistency.

This matches the product UX; no issues spotted.


240-242: Helper reads well.

Copy reads clearly and pluralization is correct.


186-205: No further action needed—getTasks returns Task[] as expected.

I verified that in site/src/api/api.ts the method is declared as:

getTasks = async (filter: TasksFilter): Promise<Task[]> => {
  // …
  return workspaces.workspaces.map(workspace => ({
    workspace,
    prompt: prompts.prompts[workspace.latest_build.id],
  }));
};

which clearly returns an array of Task objects, matching the Promise<Task[]> signature and satisfying initialData: [].

site/src/modules/dashboard/Navbar/NavbarView.stories.tsx (1)

2-7: Good inclusion of workspace fixtures.

Using MockWorkspace and MockWorkspaceAppStatus makes the story realistic.

Copy link
Member

@aslilac aslilac left a comment

Choose a reason for hiding this comment

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

nice!

@BrunoQuaresma BrunoQuaresma merged commit cde5b62 into main Aug 22, 2025
35 checks passed
@BrunoQuaresma BrunoQuaresma deleted the bq/19323 branch August 22, 2025 18:24
@github-actions github-actions bot locked and limited conversation to collaborators Aug 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tasks: Display the number of idle tasks in the Tasks nav item
3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy