Skip to content

Trigger page UI optimizations#2253

Merged
dimaMachina merged 17 commits intomainfrom
trigger-ui-optimizations
Mar 4, 2026
Merged

Trigger page UI optimizations#2253
dimaMachina merged 17 commits intomainfrom
trigger-ui-optimizations

Conversation

@Gaurav-Narayan-Varma
Copy link
Copy Markdown
Contributor

@Gaurav-Narayan-Varma Gaurav-Narayan-Varma commented Feb 23, 2026

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 23, 2026

🦋 Changeset detected

Latest commit: 141931b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@inkeep/agents-manage-ui Patch
@inkeep/agents-api Patch
@inkeep/agents-cli Patch
@inkeep/agents-core Patch
@inkeep/agents-email Patch
@inkeep/agents-mcp Patch
@inkeep/agents-sdk Patch
@inkeep/agents-work-apps Patch
@inkeep/ai-sdk-provider Patch
@inkeep/create-agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agents-manage-ui Ready Ready Preview, Comment Mar 4, 2026 8:50pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
agents-api Ignored Ignored Preview Mar 4, 2026 8:50pm
agents-docs Skipped Skipped Mar 4, 2026 8:50pm

Request Review

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(4) Total Issues | Risk: Medium

🟠⚠️ Major (3) 🟠⚠️

🟠 1) triggers-tabs.tsx:17 Missing Suspense boundary for useSearchParams

Issue: The TriggersTabs component uses useSearchParams() (line 17) but is not wrapped in a Suspense boundary. Per Next.js App Router requirements, useSearchParams always requires a Suspense boundary in pages that can be statically rendered, otherwise the entire page becomes client-side rendered.

Why: Without a Suspense boundary around the component using useSearchParams, Next.js will bail out to client-side rendering for the entire page. This defeats the benefit of the RSC data fetching optimization introduced in this PR, as the page cannot be statically rendered or streamed.

Fix: Wrap TriggersTabs in a Suspense boundary in page.tsx:

import { Suspense } from 'react';

// In TriggersPage:
<Suspense fallback={null}>
  <TriggersTabs
    scheduledContent={...}
    webhooksContent={...}
  />
</Suspense>

Alternatively, pass the initial tab value from the server component to avoid needing useSearchParams in the client component.

Refs:


🟠 2) page.tsx:36-50 Error handling regression — errors now show generic message

Issue: The previous implementation had a try-catch with FullPageError that provided context-specific error messages (context="triggers"). The new RSC tab content components have no error handling — errors bubble up to the [tenantId]/error.tsx boundary which shows a generic "Something went wrong" message.

Why: Users will see less actionable error messages when data fetching fails. Instead of "Failed to load triggers", they see "Something went wrong. An unexpected error occurred." This degrades the debugging experience for both users and support teams.

Fix: Either:

  1. Add error boundaries around each Suspense-wrapped tab content:
import { ErrorBoundary } from 'react-error-boundary';

<ErrorBoundary fallback={<FullPageError errorCode="fetch-error" context="scheduled triggers" />}>
  <Suspense fallback={<TabSkeleton />}>
    <ScheduledTabContent tenantId={tenantId} projectId={projectId} />
  </Suspense>
</ErrorBoundary>
  1. Or keep page-level try-catch with the new pattern by catching in the RSC content components and re-throwing with context.

Refs:


🟠 3) project-triggers.ts:51,78 Redundant fetchAgents calls when both tabs load

Issue: Both fetchProjectTriggers (line 51) and fetchProjectScheduledTriggers (line 78) independently call fetchAgents(tenantId, projectId). Since the RSC content components execute in parallel via separate Suspense boundaries, this results in two identical API calls for the same data.

Why: This doubles the agents API load and adds unnecessary latency. Previously, fetchAgents was called once in page.tsx and passed to TriggersTabs as a prop.

Fix: Add React's cache() wrapper to fetchAgents in agent-full-client.ts to deduplicate across the request:

// agent-full-client.ts
import { cache } from 'react';

export const fetchAgents = cache(async (
  tenantId: string,
  projectId: string
): Promise<ListResponse<Agent>> => {
  // ... existing implementation
});

This ensures the same request is deduped within a single render tree.

Refs:


Inline Comments:

  • 🟠 Major: triggers-tabs.tsx:31 URL state pattern diverges from established convention
  • 🟡 Minor: scheduled-tab-panel.tsx:30-32 Unnecessary useEffect to sync initialTriggers

💭 Consider (2) 💭

💭 1) scheduled-tab-panel.tsx:27 / webhooks-tab-panel.tsx:21 Agent filter state is now independent per tab

Issue: Each tab panel now has its own useState for agentFilter. Previously, a single filter state was shared across both tabs. This means if a user filters by "Agent A" on Scheduled and switches to Webhooks, the filter resets.

Why: This may be intentional (tab-specific filters) or a regression (users expected persistence). Consider whether this matches product expectations.

Fix: If persistence is desired, lift agentFilter state to a parent component or persist in URL search params.


💭 2) webhooks-tab-panel.tsx Webhook tab lacks polling that scheduled tab has

Issue: The Scheduled tab polls every 3 seconds to refresh trigger data, but the Webhooks tab does not. Users on Webhooks won't see updates without manually refreshing.

Why: This asymmetry may be intentional — scheduled triggers have runtime state (next run time) while webhook triggers are static configuration. If it's intentional, the difference is acceptable.

🧹 While You're Here (1) 🧹

🧹 1) project-triggers.ts:62-64, 89-91, 127-129 Silent catch blocks return empty arrays without logging

Issue: (Pre-existing) When individual agent or trigger fetches fail, errors are completely swallowed with catch { return []; }. No logging, no user feedback.

Why: Users see a partial list with no indication that some agents failed to load. API errors, auth issues, or network problems are invisible. This makes debugging difficult.

Fix: Add logging with context:

catch (error) { 
  console.error('Failed to fetch triggers for agent', agent.id, error); 
  return []; 
}

🚫 REQUEST CHANGES

Summary: This PR introduces a good architectural pattern for tab-level data fetching with Suspense, but has a few issues that should be addressed before merging: (1) missing Suspense boundary for useSearchParams, (2) error handling regression that degrades user experience, and (3) redundant API calls. The URL state pattern change is valid but introduces inconsistency with other tab components — consider whether to adopt this as the new standard.

Discarded (3)
Location Issue Reason Discarded
project-triggers/index.ts Barrel export not updated for new components Page imports directly by path consistently; no barrel export convention violated
page.tsx:17-31 TabSkeleton defined inline rather than extracted Acceptable pattern per codebase conventions; composed skeletons are typically defined where used
General Standards review found no issues No issues to report
Reviewers (6)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-frontend 4 2 0 0 1 0 1
pr-review-product 5 1 2 0 0 0 2
pr-review-consistency 4 1 0 0 1 0 2
pr-review-architecture 3 1 0 0 0 0 2
pr-review-errors 5 0 0 1 0 0 4
pr-review-standards 0 0 0 0 0 0 0
Total 21 5 2 1 2 0 11

Note: Many findings from different reviewers addressed the same underlying issues (error handling, URL pattern, redundant fetches) and were merged during deduplication.

Comment on lines +30 to +32
useEffect(() => {
setTriggers(initialTriggers);
}, [initialTriggers]);
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.

🟡 Minor: Unnecessary useEffect to sync initialTriggers to state

Issue: This useEffect syncs initialTriggers prop to local state, causing an extra render cycle when the prop changes.

Why: Per React best practices, deriving state from props should happen during render, not in effects. The component renders once with stale state, then the effect triggers a second render with updated state.

Fix: Remove this effect — the initial useState(initialTriggers) already handles initialization. Since this is an RSC pattern where the component remounts on navigation rather than receiving new props, this effect is not needed.

Suggested change
useEffect(() => {
setTriggers(initialTriggers);
}, [initialTriggers]);

Refs:

params.set('tab', tab);
router.replace(`${pathname}?${params.toString()}`, { scroll: false });
params.set('tab', newTab);
window.history.replaceState(null, '', `${pathname}?${params.toString()}`);
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.

🟠 MAJOR: URL state pattern diverges from established convention

Issue: This uses window.history.replaceState for tab URL updates, while analogous components (e.g., evaluations-tabs.tsx, dataset-tabs.tsx) use router.replace().

Why: The performance benefit is real (avoids Next.js router overhead), but this creates a split-world where two patterns coexist for the same use case. Future contributors won't know which pattern to follow. Additionally, window.history.replaceState bypasses Next.js navigation state management entirely — any middleware, analytics, or navigation listeners tied to the router won't fire.

Fix: Either:

  1. Keep this pattern but document it as the new standard and plan to migrate other tabs components
  2. Use router.replace() to match the established convention:
const router = useRouter();
router.replace(`${pathname}?${params.toString()}`, { scroll: false });

Refs:

Copy link
Copy Markdown
Contributor Author

@Gaurav-Narayan-Varma Gaurav-Narayan-Varma Feb 23, 2026

Choose a reason for hiding this comment

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

Fair point, but at the same time switching tabs shouldn't trigger another server round trip. The app becomes very slow at that point- would suggest applying this pattern more broadly.

Copy link
Copy Markdown
Contributor

@sarah-inkeep sarah-inkeep Feb 23, 2026

Choose a reason for hiding this comment

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

hmm I’m a bit worried that using window.history.replaceState instead of router.replace could cause future bugs — e.g. if another component starts using useSearchParams for the tab, it won’t update when the tab changes. Maybe we could at least add some comments around why this decision was made if there aren't any alternatives

@github-actions github-actions Bot deleted a comment from claude Bot Feb 23, 2026
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) New Issues | (5) Pending from Prior Review | Risk: Medium

Delta Review

This re-review covers only the changes since the previous automated review:

Commit: 26bf0c5c6 removed unused index

The delta is a single-line deletion of the barrel export file agents-manage-ui/src/components/project-triggers/index.ts:

- export { TriggersTabs } from './triggers-tabs';

Delta is clean. The page.tsx now imports TriggersTabs directly from the path (@/components/project-triggers/triggers-tabs), so the barrel export is no longer needed. No issues with this cleanup.


🕐 Pending Recommendations (5)

The following issues from the prior review remain unaddressed:

  • 🟠 triggers-tabs.tsx:17 Missing Suspense boundary for useSearchParams — entire page may bail out to CSR
  • 🟠 page.tsx:36-50 Error handling regression — errors now show generic message instead of context-specific
  • 🟠 project-triggers.ts:51,78 Redundant fetchAgents calls when both tabs load — consider React cache() wrapper
  • 🟠 triggers-tabs.tsx:31 URL state pattern diverges from established convention (window.history.replaceState vs router.replace())
  • 🟡 scheduled-tab-panel.tsx:30-32 Unnecessary useEffect to sync initialTriggers to state

🚫 REQUEST CHANGES

Summary: The delta commit (removing unused barrel export) is clean and introduces no new issues. However, the prior review raised 3 Major and 2 Minor issues that remain unaddressed. The most critical are: (1) missing Suspense boundary for useSearchParams which may cause the page to bail out to client-side rendering, defeating the optimization goal, and (2) error handling regression that degrades user experience when data fetching fails. Please address the pending recommendations before merging.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — delta too trivial

Note: The delta was a single-line file deletion, so no reviewer subagents were dispatched. Prior findings carry forward as Pending Recommendations.

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(1) New Issue | (4) Pending from Prior Review | Risk: Medium

Delta Review

This re-review covers only the changes since the previous automated review:

Commit: 4fe29edaa removed unnecessary useeffect

The delta removes the unnecessary useEffect that synced initialTriggers to state — this addresses the prior Minor finding. ✅

However, the removal appears to have introduced an accidental artifact:

🟡 Minor (1) 🟡

Inline Comments:

  • 🟡 Minor: scheduled-tab-panel.tsx:37 Stray 2; dead code statement

🕐 Pending Recommendations (4)

The following issues from prior reviews remain unaddressed:

  • 🟠 triggers-tabs.tsx:17 Missing Suspense boundary for useSearchParams — page may bail out to CSR
  • 🟠 page.tsx:36-50 Error handling regression — errors now show generic message instead of context-specific
  • 🟠 project-triggers.ts:51,78 Redundant fetchAgents calls when both tabs load — consider React cache() wrapper
  • 🟠 triggers-tabs.tsx:31 URL state pattern diverges from established convention

Re: URL state pattern — The author's response about router.replace() triggering server round trips is a valid concern. If this is the intended pattern going forward for performance-sensitive tab switches, consider:

  1. Documenting this as the new standard for tab URL state
  2. Planning migration of other tab components (evaluations-tabs, dataset-tabs) for consistency

💡 APPROVE WITH SUGGESTIONS

Summary: The delta commit successfully addresses the unnecessary useEffect finding from the prior review, but introduces a minor typo (2; dead code on line 37) that should be removed. The 4 pending Major/Minor issues from prior reviews remain — 3 are blocking concerns (Suspense boundary, error handling, redundant fetches) and 1 is a consistency question with valid pushback from the author. Once the stray 2; is removed and the pending items are considered, this PR is in good shape.

Discarded (0)

No items discarded in this delta review.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — delta trivial

Note: The delta was a 5-line change in a single file; no reviewer subagents were dispatched. The stray 2; was identified during direct orchestrator analysis.

setTriggers(updatedTriggers);
} catch (error) {
console.error('Failed to fetch scheduled triggers:', error);
2;
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.

🟡 Minor: Stray dead code statement

Issue: This line contains a stray 2; statement that does nothing — appears to be an accidental edit artifact from removing the useEffect.

Why: Dead code confuses future readers and may trigger linter warnings.

Fix:

Suggested change
2;

Refs:

  • Introduced in commit 4fe29edaa ("removed unnecessary useeffect")

@vercel vercel Bot temporarily deployed to Preview – agents-docs February 23, 2026 06:20 Inactive
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) New Issues | (3) Pending from Prior Review | Risk: Medium

Delta Review

This re-review covers only the changes since the previous automated review:

Commit: c85531d33 removed stray 2

The delta removes the stray 2; dead code statement — this addresses the prior Minor finding. ✅


🕐 Pending Recommendations (3)

The following issues from prior reviews remain unaddressed:

  • 🟠 triggers-tabs.tsx:17 Missing Suspense boundary for useSearchParams — page may bail out to CSR
  • 🟠 page.tsx:36-50 Error handling regression — errors now show generic message instead of context-specific
  • 🟠 project-triggers.ts:51,78 Redundant fetchAgents calls when both tabs load — consider React cache() wrapper

Note on URL state pattern: The author's response about router.replace() triggering server round trips is valid and accepted. The window.history.replaceState approach is a reasonable performance optimization for tab switching. If this becomes the standard pattern, consider documenting it for future contributors and migrating other tab components for consistency.


💡 APPROVE WITH SUGGESTIONS

Summary: The delta commit successfully addresses the stray 2; dead code from the prior review — nice cleanup! 🎉 There are still 3 pending Major recommendations from the original review that are worth considering before merge: (1) wrapping TriggersTabs in a Suspense boundary for useSearchParams, (2) adding error boundaries for better error messaging, and (3) using React cache() to dedupe fetchAgents calls. These are all incremental improvements that could be addressed in follow-up work if preferred.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — delta trivial

Note: The delta was a single-line deletion fixing a prior finding; no reviewer subagents were dispatched.

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) New Issues | (2) Pending from Prior Review | Risk: Low

Delta Review

This re-review covers only the changes since the previous automated review:

Commit: 3dc70f8ae added changeset

The delta adds a changeset file for the patch release:

---
"@inkeep/agents-manage-ui": patch
---

Fix trigger page performance issues re: initial page load and tab switching

Delta is clean. The changeset correctly describes the PR's intent and follows the expected format. No issues.


🕐 Pending Recommendations (2)

After re-examining the prior findings with fresh codebase exploration, I've reassessed each recommendation:

Still Valid:

  • 🟠 project-triggers.ts:51,78 Redundant fetchAgents calls when both tabs load

    • Both fetchProjectTriggers and fetchProjectScheduledTriggers independently call fetchAgents(tenantId, projectId)
    • Since the RSC content components execute in parallel via separate Suspense boundaries, this results in two identical API calls
    • Fix: Add React's cache() wrapper to fetchAgents (similar to how getFullAgent is already wrapped at line 112)
  • 🟡 page.tsx:36-50 Error handling removed — now uses generic tenant error boundary

    • The previous implementation had try-catch with FullPageError(context="triggers") providing context-specific messages
    • The new RSC pattern relies on the generic [tenantId]/error.tsx boundary which shows "Something went wrong"
    • Impact: Lower-fidelity error messages when data fetching fails, but not a blocker

Closed/Accepted:

  • URL state pattern (window.history.replaceState)Author's response about avoiding server round trips is valid. This is an acceptable performance optimization for tab switching.

  • Missing Suspense boundary for useSearchParams — After exploration, I confirmed the page uses force-dynamic, so static rendering concerns don't apply. The streaming behavior is acceptable since the inner content components ARE wrapped in Suspense.


💡 APPROVE WITH SUGGESTIONS

Summary: The delta (changeset addition) is clean and the PR is ready to merge. 🎉 Two recommendations remain for consideration: (1) wrapping fetchAgents with React cache() to dedupe the parallel API calls, and (2) optionally adding error boundaries for more descriptive error messages. Neither is blocking — the performance optimization goal of the PR is achieved.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — delta trivial

Note: The delta was a single changeset file addition; no reviewer subagents were dispatched. Prior findings were re-assessed based on fresh codebase exploration.

@github-actions github-actions Bot deleted a comment from claude Bot Mar 4, 2026
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) New Issues | (2) Pending from Prior Reviews | Risk: Low

Delta Review

This re-review covers only the changes since the previous automated review:

Commit: 4dd8d5433 Merge branch 'main' into trigger-ui-optimizations

The delta is a merge commit incorporating changes from main into the PR branch. The merged changes relate to tool approval denial reason propagation (PR #2500, #2520) and are unrelated to this PR's trigger page optimizations.

PR-specific files are unchanged:

  • new-trigger-dialog.tsx — no changes
  • scheduled-tab-content.tsx — no changes
  • scheduled-tab-panel.tsx — no changes
  • triggers-tabs.tsx — no changes
  • webhooks-tab-content.tsx — no changes
  • webhooks-tab-panel.tsx — no changes
  • page.tsx (triggers) — no changes
  • project-triggers.ts (API) — no changes

Delta is clean. The merge brings the branch up to date with main without introducing new issues to the PR code.


🕐 Pending Recommendations (2)

The following items from prior reviews remain for consideration:

  • 🟠 project-triggers.ts:51,78 Redundant fetchAgents calls — Both fetchProjectTriggers and fetchProjectScheduledTriggers independently call fetchAgents(). With parallel Suspense boundaries, this results in duplicate API calls. Consider wrapping fetchAgents with React cache() (similar to how getFullAgent is wrapped).

  • 🟡 new-trigger-dialog.tsx:63 Dialog cancel doesn't reset agent selection state — The Cancel button closes the dialog but doesn't reset selectedAgent, causing stale state on reopen. (Identified by Ito QA - EDGE-6). See inline comment for fix.

🟡 Minor (1) 🟡

Inline Comments:

  • 🟡 Minor: new-trigger-dialog.tsx:63 Dialog cancel doesn't reset agent selection state

✅ APPROVE

Summary: The delta (merge from main) is clean and introduces no new issues to the PR code. 🎉 The PR achieves its stated goal of fixing trigger page performance issues for initial load and tab switching. Two items remain for consideration: (1) wrapping fetchAgents with React cache() to dedupe parallel API calls (optimization), and (2) resetting dialog state on cancel (UX bug from Ito QA). Neither is blocking — they can be addressed in follow-up work if preferred.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — merge-only delta

Note: The delta was a merge commit with no PR-specific code changes; no reviewer subagents were dispatched. Prior findings carry forward as Pending Recommendations.

className="w-[var(--radix-popover-trigger-width)]"
/>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setOpen(false)}>
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.

🟡 Minor: Dialog cancel doesn't reset agent selection state

Issue: The Cancel button only closes the dialog via setOpen(false) but doesn't reset selectedAgent state. If a user selects an agent, cancels, and reopens the dialog, the previous selection persists.

Why: This creates confusing UX where the dialog remembers stale state across open/close cycles. Users expect a fresh dialog when reopening. (Identified by Ito QA testing - EDGE-6)

Fix:

Suggested change
<Button variant="outline" onClick={() => setOpen(false)}>
<Button variant="outline" onClick={() => { setSelectedAgent(''); setOpen(false); }}>

Alternatively, reset state in onOpenChange:

<Dialog open={open} onOpenChange={(isOpen) => {
  if (!isOpen) setSelectedAgent('');
  setOpen(isOpen);
}}>

Refs:

@vercel vercel Bot temporarily deployed to Preview – agents-docs March 4, 2026 20:10 Inactive
@dimaMachina
Copy link
Copy Markdown
Collaborator

@claude verify and add a changeset

@inkeep-internal-ci
Copy link
Copy Markdown
Contributor

inkeep-internal-ci Bot commented Mar 4, 2026

Claude finished @dimaMachina's task in 1m 28s —— View job


Verify and Add Changeset

  • Review current changes and existing changeset
  • Verify the code — CI was running (Auto Format passed, CI/Cypress in progress). All changes scoped to agents-manage-ui only.
  • Improve changeset message — updated to be more descriptive per repo guidelines
  • Fix dialog cancel state reset bug (EDGE-6 from Ito QA) — dialog now resets selectedAgent on close via onOpenChange
  • Push changes

Summary

A changeset already existed (deep-beige-donkey.md). I made two changes:

  1. Improved changeset message — from generic "Fix trigger page performance issues" to a more descriptive message explaining the RSC/Suspense/nuqs approach
  2. Fixed dialog cancel bug (EDGE-6) — NewTriggerDialog now resets selectedAgent state when closing, so reopening shows a fresh dialog

Commit: 9e1f762
|

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) New Issues | (2) Pending from Prior Reviews | Risk: Low

Delta Review

This re-review covers only the changes since the previous automated review:

Commit: d16aa2caf polish

The delta refactors the composition pattern:

  • page.tsx — Moves TabsContent from TriggersTabs to the page, nesting them as children
  • triggers-tabs.tsx — Simplified to accept children prop instead of separate scheduledContent/webhooksContent props

Delta is clean. This is a good architectural refinement. By moving TabsContent to the page level (inside the RSC), the Suspense boundaries wrap the actual content components directly where they're defined. This pattern:

  • Improves composition flexibility
  • Makes the page structure more explicit
  • Aligns with React Server Component best practices where async content boundaries are clearer at the page level

🟡 Minor (1) 🟡

Inline Comments:

  • 🟡 Minor: new-trigger-dialog.tsx:63 Dialog cancel doesn't reset agent selection state

🕐 Pending Recommendations (2)

The following items from prior reviews remain for consideration:

  • 🟠 project-triggers.ts:51,78 Redundant fetchAgents calls — Both fetchProjectTriggers and fetchProjectScheduledTriggers independently call fetchAgents(). With parallel Suspense boundaries, this results in duplicate API calls. Consider wrapping fetchAgents with React cache() (similar to how getFullAgent is wrapped at line 112).

  • 🟡 new-trigger-dialog.tsx:63 Dialog cancel doesn't reset agent selection state — See inline comment for fix. (Identified by Ito QA - EDGE-6)


✅ APPROVE

Summary: The delta (composition pattern refactor) is clean and improves the page structure. 🎉 The PR achieves its stated goal of fixing trigger page performance issues for initial load and tab switching. Two items remain for consideration: (1) wrapping fetchAgents with React cache() to dedupe parallel API calls, and (2) resetting dialog state on cancel. Neither is blocking — they can be addressed in follow-up work if preferred.

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — delta trivial

Note: The delta was a composition pattern refactor (14 additions, 25 deletions across 2 files); no reviewer subagents were dispatched. Prior findings carry forward as Pending Recommendations.

className="w-[var(--radix-popover-trigger-width)]"
/>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setOpen(false)}>
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.

🟡 Minor: Dialog cancel doesn't reset agent selection state

Issue: The Cancel button only closes the dialog via setOpen(false) but doesn't reset selectedAgent state. If a user selects an agent, cancels, and reopens the dialog, the previous selection persists.

Why: This creates confusing UX where the dialog remembers stale state across open/close cycles. Users expect a fresh dialog when reopening. (Identified by Ito QA testing - EDGE-6)

Fix:

Suggested change
<Button variant="outline" onClick={() => setOpen(false)}>
<Button variant="outline" onClick={() => { setSelectedAgent(''); setOpen(false); }}>

Alternatively, reset state in onOpenChange:

<Dialog open={open} onOpenChange={(isOpen) => {
  if (!isOpen) setSelectedAgent('');
  setOpen(isOpen);
}}>

Refs:

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) New Issues | Risk: Low

Delta Review

This re-review covers only the changes since the previous automated review:

Commits:

  • 9e1f76265 — fix: reset dialog agent selection on close, improve changeset message
  • cbd0689dc — dedupe fetchAgents req

✅ Both Pending Issues Resolved

1. Dialog state reset bug (EDGE-6) — Fixed

The NewTriggerDialog now resets selectedAgent when the dialog closes via onOpenChange:

<Dialog
  open={open}
  onOpenChange={(isOpen) => {
    if (!isOpen) setSelectedAgent('');
    setOpen(isOpen);
  }}
>

This correctly handles all close paths (Cancel button, overlay click, Escape key) by resetting state in the onOpenChange callback rather than only on Cancel click. ✅

2. Redundant fetchAgents calls — Fixed

The fetchAgents function is now wrapped with React's cache():

async function $fetchAgents(tenantId: string, projectId: string): Promise<ListResponse<Agent>> {
  // ... implementation
}

export const fetchAgents = cache($fetchAgents);

This follows the existing pattern used by getFullAgent (line 111) and ensures that when both fetchProjectTriggers and fetchProjectScheduledTriggers call fetchAgents() in parallel Suspense boundaries, the request is deduplicated within the same render tree. ✅

3. Changeset improved — Good

The changeset message was updated from generic "Fix trigger page performance issues" to a more descriptive message explaining the RSC/Suspense/nuqs approach, per repo guidelines.


✅ APPROVE

Summary: The delta successfully addresses both pending issues from the prior review — the dialog state reset bug identified by Ito QA and the redundant fetchAgents API calls. Both fixes follow established codebase patterns and are correctly implemented. 🎉

The PR is ready to merge. It achieves its stated goal of improving trigger page performance by:

  • Splitting tab content into separate RSC components with Suspense boundaries
  • Using nuqs for client-side tab switching (no server round trips)
  • Deduplicating fetchAgents calls with React cache()
Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — delta trivial

Note: The delta was 2 commits addressing previously identified issues; no reviewer subagents were dispatched.

@github-actions github-actions Bot deleted a comment from claude Bot Mar 4, 2026
@vercel vercel Bot temporarily deployed to Preview – agents-docs March 4, 2026 20:47 Inactive
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) New Issues | Risk: Low

Delta Review

This re-review covers only the changes since the previous automated review:

Commit: 141931bce use dialog.close

The delta refactors NewTriggerDialog to use idiomatic Radix patterns:

-import { useState } from 'react';
+import { DialogClose } from '@/components/ui/dialog';
...
-const [open, setOpen] = useState(false);
-<Dialog open={open} onOpenChange={(isOpen) => { if (!isOpen) setSelectedAgent(''); setOpen(isOpen); }}>
+<Dialog onOpenChange={(isOpen) => { if (!isOpen) setSelectedAgent(''); }}>
...
-<Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
+<DialogClose asChild><Button variant="outline">Cancel</Button></DialogClose>

Delta is clean and improves the code. This change:

  • Simplifies the dialog by switching from controlled to uncontrolled mode
  • Uses Radix's DialogClose component for the Cancel button (idiomatic pattern)
  • Preserves the EDGE-6 bug fixselectedAgent is still reset via onOpenChange when the dialog closes
  • Minor CSS improvement: w-(--radix-popover-trigger-width) is the modern Tailwind CSS syntax for CSS variables

✅ APPROVE

Summary: The delta is a clean refactor that simplifies the dialog implementation by using Radix's uncontrolled mode and DialogClose component. All previously identified issues remain resolved. The PR achieves its stated goal of improving trigger page performance through RSC/Suspense patterns and is ready to merge. 🎉

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
None dispatched — delta trivial

Note: The delta was a single-file refactor (8 additions, 9 deletions) simplifying the dialog pattern; no reviewer subagents were dispatched.

@dimaMachina dimaMachina merged commit 19e16cc into main Mar 4, 2026
13 checks passed
@dimaMachina dimaMachina deleted the trigger-ui-optimizations branch March 4, 2026 20:53
@claude claude Bot mentioned this pull request Mar 4, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants