Add tabbed session inbox to the Duo panel behind a feature flag
What does this MR do and why?
Adds a tabbed session inbox to the Duo side panel's Sessions view behind duo_panel_session_inbox. The full page at /-/automate/agent-sessions is unchanged; flag off renders the existing flat list exactly as before.
The inbox has a Needs a decision tab and an All tab driven by one GraphQL document with two aliased duoWorkflowWorkflows connections on a 10-second poll. needsDecision pins statusGroup: AWAITING_INPUT and first: 20 as document literals so the search bar's status token cannot redefine the tab's meaning. all takes $statusGroup and the cursor variables and is the only tab that paginates. type is a variable defaulted to non_foundational_chat_agents, which keeps Duo Chat threads out of both tabs.
The flag is resolved in getNamespaceIndexComponent via a new side_panel namespace passed by init_duo_panel.js; the full page still passes user. The decision tab has its own empty state rather than delegating to agent_flow_list.vue, whose copy says "no results matching your search" — wrong for a fixed-meaning tab. Skeletons gate on loading && !inbox so a poll overlapping a refetch cannot blank the tabs after results arrive. Count badges are a follow-up MR.
New files: panel/agent_session_inbox.vue, panel/agent_session_inbox_tab.vue (the extracted per-tab body), and graphql/queries/get_user_agent_flow_inbox.query.graphql. The side_panel namespace is wired through router/utils.js, constants.js, and init_duo_panel.js. Covered by component specs for agent_session_inbox.vue and agent_session_inbox_tab.vue, plus router util specs. MSW integration coverage follows in #621834; master restructured the MSW harness mid-flight and the port hit a separate blocker, so it is not held in this MR.
References
- Issue: #616493 (closed)
- Parent epic: gitlab-org#23179 (closed)
- Builds on !250654 (merged) and !250926 (merged), both merged
- Follow-up for the MSW integration spec: #621834
- Feature flag shipped in !250917 (merged), merged
Screenshots or screen recordings
Recorded at c7938f6b, before the rebase onto master. The inbox
code is unchanged since. GDK seeded with 26 sessions: 3 awaiting input, 22
running or finished, and 1 chat-definition session that should appear in
neither tab. Pre-existing awaiting rows were demoted to finished so the
decision-tab count was unambiguous.
Needs a decision tab, listing only the three awaiting-input sessions.
All tab, page one at 20 rows.
Search narrows the All tab.
Next page keeps the filter, leaving the two remaining rows.
The decision tab paginates on its own cursor.
Decision tab under a filter that matches nothing.
All tab filter surviving a page change.
Decision-tab empty state, distinct from the shared "no results" copy.
Its button moves selection to the All tab.
Flag off: the previous flat list, no tabs.
Sort-direction change was not re-verified after the loading fix; everything above was observed directly, with the GraphQL variables read off the wire.
How to set up and validate locally
- In a Rails console:
Feature.enable(:duo_panel_session_inbox) - Reload, open the Duo panel, navigate to Sessions. Both tabs render.
- Submit a search with the magnifier, then click Next on the All tab. Confirm the filter holds on page 2.
Feature.disable(:duo_panel_session_inbox)and reload. The previous flat list is unchanged.
Note: session search matches the goal and workflow_definition fields, not the title shown in the row. Searching for a visible title can legitimately return no results. Pre-existing behaviour, not a bug introduced here.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.









