Skip to content

fix: show AI chat action buttons after streaming completes - #144

Merged
2witstudios merged 1 commit into
masterfrom
claude/fix-chat-buttons-streaming-zz3wv
Dec 28, 2025
Merged

2witstudios merged 1 commit into
masterfrom
claude/fix-chat-buttons-streaming-zz3wv

Conversation

@2witstudios

@2witstudios 2witstudios commented Dec 28, 2025 •

Copy link
Copy Markdown
Owner

The message action buttons (edit, delete, retry, undo) were not visible after AI streaming finished because they were wrapped inside a {createdAt && ...} conditional. During streaming, the AI SDK's useChat hook creates messages without a createdAt timestamp (only populated when saved to DB), causing the entire footer with buttons to not render.

Fixed by separating the button rendering from the timestamp condition:

  • Buttons now always render when handlers are provided
  • Timestamp only shows when createdAt exists

Summary by CodeRabbit

  • Refactor
    • Enhanced message footer rendering in chat components. Footer sections now render with improved conditional logic. Timestamps and edit indicators display when available, while Edit/Delete action buttons appear based on editing state and handler availability.

✏️ Tip: You can customize this high-level summary in your review settings.

The message action buttons (edit, delete, retry, undo) were not visible
after AI streaming finished because they were wrapped inside a
`{createdAt && ...}` conditional. During streaming, the AI SDK's useChat
hook creates messages without a createdAt timestamp (only populated when
saved to DB), causing the entire footer with buttons to not render.

Fixed by separating the button rendering from the timestamp condition:
- Buttons now always render when handlers are provided
- Timestamp only shows when createdAt exists
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Dec 28, 2025 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Refactored footer rendering logic in two message renderer components. The footer section now renders unconditionally with conditional timestamp display based on createdAt existence. Action buttons (Edit/Delete) are conditionally rendered based on editing state and handler availability, rather than being tied to createdAt.

Changes

Cohort / File(s) Summary
Message Footer Rendering
apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx, apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
Refactored footer to render unconditionally. Timestamp display now conditional on createdAt existence. Action buttons (Edit/Delete) moved to separate conditional rendering based on onEdit, onDelete, and isEditing state rather than createdAt presence.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 The footer hops freely, no longer bound,
Timestamps dance when createdAt's found,
Edit and Delete now leap on their own,
Rendering cleaner in this newfound zone!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing visibility of AI chat action buttons after streaming completes by decoupling button rendering from the createdAt condition.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/fix-chat-buttons-streaming-zz3wv

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6d4113 and de2f16b.

📒 Files selected for processing (2)
  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Never use any types - always use proper TypeScript types
Use camelCase for variable and function names
Use UPPER_SNAKE_CASE for constants
Use PascalCase for type and enum names
Use kebab-case for filenames, except React hooks (camelCase with use prefix), Zustand stores (camelCase with use prefix), and React components (PascalCase)
Lint with Next/ESLint as configured in apps/web/eslint.config.mjs
Message content should always use the message parts structure with { parts: [{ type: 'text', text: '...' }] }
Use centralized permission functions from @pagespace/lib/permissions (e.g., getUserAccessLevel, canUserEditPage) instead of implementing permission logic locally
Always use Drizzle client from @pagespace/db package for database access
Use ESM modules throughout the codebase

**/*.{ts,tsx}: Never use any types - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting

Files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/*.tsx: React component files should use PascalCase (e.g., UserProfile.tsx)
Use @dnd-kit for drag-and-drop functionality
Use Zustand for client state management
Use SWR for server state management and caching

Files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Format code with Prettier

Files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
**/*.{tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS and shadcn/ui components for styling and UI

Files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
apps/web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/src/**/*.{ts,tsx}: Use message parts structure for message content: { parts: [{ type: 'text', text: '...' }] }
For database access, always use Drizzle client from @pagespace/db: import { db, pages } from '@pagespace/db';
Use centralized Drizzle ORM with PostgreSQL for all database operations - no direct SQL or other ORMs
Use Socket.IO for real-time collaboration features - imported from the realtime service at port 3001
Use Vercel AI SDK with async/await for all AI operations and streaming
Use Next.js 15 App Router and TypeScript for all routes and components

Files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
apps/web/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/src/components/**/*.{ts,tsx}: When document editing, register editing state with useEditingStore.getState().startEditing() to prevent UI refreshes, and clean up in return statement
When AI is streaming, register streaming state with useEditingStore.getState().startStreaming() to prevent UI refreshes, and clean up in return statement
For SWR data fetching with editing protection, use isPaused: () => hasLoadedRef.current && isEditingActive() to allow initial fetch and only pause after, with revalidateOnFocus: false
Use Zustand for client-side state management as the primary state solution
Use SWR for server state and caching with proper configuration including revalidateOnFocus: false for editing protection
Use TipTap rich text editor with markdown support for document editing
Use Monaco Editor for code editing features
Use @dnd-kit for drag-and-drop functionality instead of other libraries
Use Tailwind CSS with shadcn/ui components for all UI styling and components

Files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
🧠 Learnings (4)
📚 Learning: 2025-12-16T19:03:59.870Z
Learnt from: 2witstudios
Repo: 2witstudios/PageSpace PR: 91
File: apps/web/src/components/ai/shared/chat/tool-calls/CompactToolCallRenderer.tsx:253-277
Timestamp: 2025-12-16T19:03:59.870Z
Learning: In apps/web/src/components/ai/shared/chat/tool-calls/CompactToolCallRenderer.tsx (TypeScript/React), use the `getLanguageFromPath` utility from `formatters.ts` to infer syntax highlighting language from file paths instead of hardcoding language values in DocumentRenderer calls.

Applied to files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
  • apps/web/src/components/ai/shared/chat/MessageRenderer.tsx
📚 Learning: 2025-12-23T18:49:41.966Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-23T18:49:41.966Z
Learning: Applies to apps/web/src/components/**/*.{ts,tsx} : Use TipTap rich text editor with markdown support for document editing

Applied to files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
📚 Learning: 2025-12-14T14:54:45.713Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T14:54:45.713Z
Learning: Applies to **/*.{ts,tsx} : Keep commits and diffs minimal and focused on specific changes

Applied to files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
📚 Learning: 2025-12-23T18:49:41.966Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-23T18:49:41.966Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : Use message parts structure for message content: `{ parts: [{ type: 'text', text: '...' }] }`

Applied to files:

  • apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx
🧬 Code graph analysis (2)
apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx (1)
apps/web/src/components/ai/shared/chat/MessageActionButtons.tsx (1)
  • MessageActionButtons (14-73)
apps/web/src/components/ai/shared/chat/MessageRenderer.tsx (1)
apps/web/src/components/ai/shared/chat/MessageActionButtons.tsx (1)
  • MessageActionButtons (14-73)
🔇 Additional comments (2)
apps/web/src/components/ai/shared/chat/CompactMessageRenderer.tsx (1)

85-104: LGTM! Footer logic correctly decouples button visibility from timestamp.

The changes successfully address the stated issue: action buttons now render during streaming when handlers are provided, independent of createdAt existence. The footer always renders with:

  • Timestamp displayed only when createdAt exists (preventing undefined values during streaming)
  • Action buttons displayed when both handlers are provided and not in editing mode

This ensures buttons are visible immediately after streaming completes, even before the message is persisted to the database.

apps/web/src/components/ai/shared/chat/MessageRenderer.tsx (1)

83-101: LGTM! Consistent implementation with CompactMessageRenderer.

The footer rendering logic matches the pattern in CompactMessageRenderer: the footer always renders, timestamp shows only when createdAt exists, and action buttons display when handlers are provided and not editing. This ensures consistent behavior across both renderers where buttons are visible during and after streaming, regardless of database persistence state.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@2witstudios
2witstudios merged commit 41bc966 into master Dec 28, 2025
3 checks passed
@2witstudios
2witstudios deleted the claude/fix-chat-buttons-streaming-zz3wv branch January 29, 2026 02:24
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.

2 participants