Repository navigation
feat(calendar): schedule agent on events + event type filter - #1147
Conversation
- Add "Run agent" section to EventModal (drive context, new events only) - Fetches drive agents from /api/drives/[driveId]/agents for picker - POST /api/calendar/events now accepts agentTrigger (agentPageId + prompt) - Validates agent exists in drive before insert, then creates calendarTriggers row - GET /api/calendar/events annotates each event with hasAgentTrigger boolean - Extend useCalendarFilterStore with hiddenEventTypes (persisted) - Drive calendar header: Events/Agents toggle chips - User calendar sidebar: Event types section with User/Agent checkboxes - filteredEvents respects hiddenEventTypes in CalendarView Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds agent-trigger scheduling for calendar events: POST accepts optional Changes
Sequence Diagram(s)sequenceDiagram
participant User as User/Client
participant Modal as EventModal
participant Agents as Agents Service
participant API as Calendar API
participant DB as Database
User->>Modal: Open new event modal (drive context)
Modal->>Agents: GET /api/drives/{driveId}/agents
Agents-->>Modal: agent list
User->>Modal: Enable agent scheduling, select agent, enter prompt, Save
Modal->>Modal: Validate agent selection & prompt
Modal->>API: POST /api/calendar/events { eventData, agentTrigger }
API->>API: Validate drive-scoped & non-recurring
API->>DB: INSERT calendar_event (+ attendees)
API->>DB: INSERT calendarTriggers {calendarEventId, agentPageId, prompt, triggerAt, ...}
DB-->>API: OK
API-->>Modal: 201 Created (hasAgentTrigger: true)
sequenceDiagram
participant View as CalendarView
participant API as Calendar API
participant Store as Calendar Filter Store
participant Sidebar as CalendarSidebar
participant User as User
View->>API: GET /api/calendar/events
API-->>View: events[] with hasAgentTrigger flags
View->>Store: read hiddenEventTypes
View->>View: filter events by hiddenEventTypes (agent/user)
View->>Sidebar: pass visibility booleans & toggle handlers
User->>Sidebar: toggle agent/user visibility
Sidebar->>Store: toggleEventType(type)
Store-->>View: updated hiddenEventTypes (subscriber)
View->>User: render filtered events
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Review rate limit: 0/1 reviews remaining, refill in 37 minutes and 37 seconds.Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a55a1ab6f9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Create agent trigger if requested (validation already done above) | ||
| if (data.agentTrigger && agentPageId && data.driveId) { | ||
| await db.insert(calendarTriggers).values({ | ||
| calendarEventId: event.id, |
There was a problem hiding this comment.
Keep trigger schedule in sync with event time changes
This POST path creates a calendar_triggers row tied to the event start time, but no linkage/update is added for later edits, so moving the event in /api/calendar/events/[eventId] will update calendar_events.startAt without updating calendar_triggers.triggerAt. In practice, a user can create a “Run agent” event, reschedule it in the calendar UI, and the agent will still fire at the original time. Since this commit introduces trigger creation from the main calendar flow, it also needs a corresponding trigger-resync path (or equivalent metadata+transaction strategy) to avoid stale executions.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in e29a432: the PATCH handler in /api/calendar/events/[eventId]/route.ts now updates calendar_triggers.triggerAt to match the new startAt when the event is rescheduled (only for status = 'pending' rows).
There was a problem hiding this comment.
Fixed in d41ed21: the PATCH handler in /api/calendar/events/[eventId]/route.ts now wraps both the event-time update and the calendar_triggers.triggerAt sync in a single db.transaction(). When startAt changes, the transaction updates calendarEvents and immediately updates any pending trigger row to the new time — only pending rows are touched so completed, failed, and cancelled triggers are not affected.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/app/api/calendar/events/route.ts`:
- Around line 573-584: The calendar trigger insert must be made atomic with the
event and attendee inserts: wrap the event creation, attendee inserts, and the
calendarTriggers insert in a single database transaction so all three commit or
rollback together; specifically, update the handler to run db.transaction (or
your ORM's transaction API) around the code that creates the event (where
event.id is produced), inserts attendees, and the
db.insert(calendarTriggers).values(...) call (referenced as calendarTriggers and
the db.insert(...).values(...) call) and ensure you use the event id returned
from the transaction-scoped insert when creating the trigger so any failure
rolls back the event and attendees to avoid partial duplicates.
- Around line 54-57: The agentTrigger.prompt Zod schema currently allows strings
of only whitespace; update the schema for agentTrigger (the agentTrigger object
in route.ts) to validate trimmed non-empty input, e.g. use
z.string().trim().min(1).max(10000) or add a .transform(s => s.trim()) followed
by .refine(s => s.length > 0) so blank prompts like " " are rejected.
In `@apps/web/src/components/calendar/CalendarSidebar.tsx`:
- Around line 110-186: The interactive filter containers currently make the
outer div focusable and handle clicks via onToggleUserEvents/onToggleAgentEvents
while the checkbox semantics (role="checkbox" and aria-checked) are on the
nested span, so screen readers won't announce the checked state; move the
accessible state to the actionable element by applying role="checkbox",
aria-checked={userEventsVisible|agentEventsVisible} and aria-label to the outer
focusable element (the divs handling onClick/onKeyDown) or replace the outer div
with a native button/input element, ensuring
onToggleUserEvents/onToggleAgentEvents remain the handlers and that the inner
span no longer duplicates role/aria attributes (keep visual checkbox markup
only).
In `@apps/web/src/components/calendar/CalendarView.tsx`:
- Around line 422-448: The new event-type filter UI added in CalendarView is
only rendered for non-user desktop layouts and isn't exposed to mobile because
MobileCalendarView is returned earlier without receiving the event-filter state
or handlers; update CalendarView to pass the isEventTypeVisible and
toggleEventType props (or a consolidated eventFilter props object) into
MobileCalendarView and implement corresponding props in MobileCalendarView to
render the same toggles (or a mobile-friendly UI) so mobile users can toggle
'user' and 'agent' filters; search for CalendarView, MobileCalendarView,
isEventTypeVisible, and toggleEventType to locate the affected code and wire the
props through.
In `@apps/web/src/components/calendar/EventModal.tsx`:
- Around line 407-468: The Run agent flow currently allows enabling scheduling
even when there are no agents; update the UI logic around canScheduleAgent /
Switch (id="schedule-agent") and the state used by selectedAgentId so the switch
is disabled (or the section replaced by an empty state) when agentsLoading is
true or agents.length === 0; ensure the Switch's disabled prop is tied to that
condition and the Select is not selectable, and when agents become unavailable
clear selectedAgentId/agentPrompt to a safe default to avoid save-time
validation loops in the save handler (e.g., when scheduleAgent is true but no
valid selectedAgentId).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1202d965-9218-4f81-a05d-9ced227587b2
📒 Files selected for processing (7)
apps/web/src/app/api/calendar/events/route.tsapps/web/src/components/calendar/CalendarSidebar.tsxapps/web/src/components/calendar/CalendarView.tsxapps/web/src/components/calendar/EventModal.tsxapps/web/src/components/calendar/calendar-types.tsapps/web/src/components/calendar/useCalendarData.tsapps/web/src/stores/useCalendarFilterStore.ts
- enforce canUserViewPage on agent trigger creation (P1) - sync trigger triggerAt when event is moved (P2) - filter cancelled/failed triggers from hasAgentTrigger - narrow event type store to 'agent'|'user' literal union - fix ARIA nesting in sidebar event type filters - guard __none sentinel in EventModal save path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/web/src/app/api/calendar/events/route.ts (2)
581-592:⚠️ Potential issue | 🟠 MajorMake event + attendee + trigger writes atomic.
If Line 583 insert fails, the event is already created and this returns 500 with partial state.
💡 Suggested refactor pattern
- // Create the event - const [event] = await db - .insert(calendarEvents) - .values({ ... }) - .returning(); - - await db.insert(eventAttendees).values({ ...creator... }); - // ...insert other attendees... - - if (data.agentTrigger && agentPageId && data.driveId) { - await db.insert(calendarTriggers).values({ ... }); - } + const event = await db.transaction(async (tx) => { + const [createdEvent] = await tx + .insert(calendarEvents) + .values({ ... }) + .returning(); + + await tx.insert(eventAttendees).values({ ...creator... }); + // ...insert other attendees via tx... + + if (data.agentTrigger && agentPageId && data.driveId) { + await tx.insert(calendarTriggers).values({ ... }); + } + + return createdEvent; + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/app/api/calendar/events/route.ts` around lines 581 - 592, The event, attendee and trigger inserts must be executed inside a single DB transaction so a failure (e.g., the calendarTriggers insert) won't leave a partially-created event; wrap the creation of the event (calendarEvents), the attendee insert (calendarAttendees) and the trigger insert (calendarTriggers) in one transaction using db.transaction and perform the inserts via the transaction object (e.g., tx.insert(...).values(...)), capture the created event id from the tx result and use it for subsequent inserts, and rollback automatically on error.
54-57:⚠️ Potential issue | 🟡 MinorReject whitespace-only agent prompts at API boundary.
Line 56 still allows
" "because.min(1)checks raw length, not trimmed content.💡 Suggested fix
agentTrigger: z.object({ agentPageId: z.string(), - prompt: z.string().min(1).max(10000), + prompt: z.string().trim().min(1).max(10000), }).optional(),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/app/api/calendar/events/route.ts` around lines 54 - 57, The prompt field in the agentTrigger schema currently uses z.string().min(1) which permits whitespace-only strings; update the agentTrigger: z.object({ agentPageId: z.string(), prompt: z.string().min(1).max(10000), }).optional() by tightening the prompt validator to reject whitespace-only input—either call .trim().min(1) if your Zod version supports trim, or add .refine(p => p.trim().length > 0, { message: "Prompt cannot be empty or whitespace only" }) (and keep the .max(10000)); modify the prompt schema in route.ts accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/app/api/calendar/events/`[eventId]/route.ts:
- Around line 244-255: The event time update and the calendarTriggers update
must be performed in a single DB transaction to avoid leaving triggers stale if
the second update fails; wrap the existing event update and the conditional
block that updates calendarTriggers (the code that calls db.update(...) on
calendar events and the block that calls db.update(calendarTriggers).set({
triggerAt: adjustedStartAt }) where eq(calendarTriggers.calendarEventId,
eventId) and status is 'pending') inside a single db.transaction (use the same
transaction handle, e.g. tx) so both updates use tx.update(...) and the
transaction is committed/rolled back atomically.
---
Duplicate comments:
In `@apps/web/src/app/api/calendar/events/route.ts`:
- Around line 581-592: The event, attendee and trigger inserts must be executed
inside a single DB transaction so a failure (e.g., the calendarTriggers insert)
won't leave a partially-created event; wrap the creation of the event
(calendarEvents), the attendee insert (calendarAttendees) and the trigger insert
(calendarTriggers) in one transaction using db.transaction and perform the
inserts via the transaction object (e.g., tx.insert(...).values(...)), capture
the created event id from the tx result and use it for subsequent inserts, and
rollback automatically on error.
- Around line 54-57: The prompt field in the agentTrigger schema currently uses
z.string().min(1) which permits whitespace-only strings; update the
agentTrigger: z.object({ agentPageId: z.string(), prompt:
z.string().min(1).max(10000), }).optional() by tightening the prompt validator
to reject whitespace-only input—either call .trim().min(1) if your Zod version
supports trim, or add .refine(p => p.trim().length > 0, { message: "Prompt
cannot be empty or whitespace only" }) (and keep the .max(10000)); modify the
prompt schema in route.ts accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7c66f810-b402-4ac1-921b-557fe0c8f006
📒 Files selected for processing (5)
apps/web/src/app/api/calendar/events/[eventId]/route.tsapps/web/src/app/api/calendar/events/route.tsapps/web/src/components/calendar/CalendarSidebar.tsxapps/web/src/components/calendar/EventModal.tsxapps/web/src/stores/useCalendarFilterStore.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/src/stores/useCalendarFilterStore.ts
- apps/web/src/components/calendar/EventModal.tsx
CalendarSidebar gained 4 required props in the new feature commit but MobileCalendarView.tsx and its test file were not updated, causing TS build failures in CI. Wire useCalendarFilterStore into MobileCalendarView and supply the new props to CalendarSidebar. Update all CalendarSidebar test renders with default values. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- wrap POST event+attendees+trigger in a single db.transaction so a trigger insert failure cannot leave a partial event in the DB - wrap PATCH event+trigger-sync in a single db.transaction so a trigger update failure cannot leave stale triggerAt - add .trim() to agentTrigger.prompt schema so whitespace-only strings are rejected server-side - disable the 'Run agent' switch and show a message when the drive has no AI agent pages, preventing a dead-end save loop Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(calendar): schedule agent on events + type filter - Add "Run agent" section to EventModal (drive context, new events only) - Fetches drive agents from /api/drives/[driveId]/agents for picker - POST /api/calendar/events now accepts agentTrigger (agentPageId + prompt) - Validates agent exists in drive before insert, then creates calendarTriggers row - GET /api/calendar/events annotates each event with hasAgentTrigger boolean - Extend useCalendarFilterStore with hiddenEventTypes (persisted) - Drive calendar header: Events/Agents toggle chips - User calendar sidebar: Event types section with User/Agent checkboxes - filteredEvents respects hiddenEventTypes in CalendarView Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(calendar): review fixes for agent scheduling - enforce canUserViewPage on agent trigger creation (P1) - sync trigger triggerAt when event is moved (P2) - filter cancelled/failed triggers from hasAgentTrigger - narrow event type store to 'agent'|'user' literal union - fix ARIA nesting in sidebar event type filters - guard __none sentinel in EventModal save path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(calendar): wire event type filter props to MobileCalendarView CalendarSidebar gained 4 required props in the new feature commit but MobileCalendarView.tsx and its test file were not updated, causing TS build failures in CI. Wire useCalendarFilterStore into MobileCalendarView and supply the new props to CalendarSidebar. Update all CalendarSidebar test renders with default values. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(calendar): atomicity, prompt trimming, and empty-agent UX - wrap POST event+attendees+trigger in a single db.transaction so a trigger insert failure cannot leave a partial event in the DB - wrap PATCH event+trigger-sync in a single db.transaction so a trigger update failure cannot leave stale triggerAt - add .trim() to agentTrigger.prompt schema so whitespace-only strings are rejected server-side - disable the 'Run agent' switch and show a message when the drive has no AI agent pages, preventing a dead-end save loop Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(calendar): update PATCH test mock for db.transaction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Test plan
🤖 Generated with Claude Code