-
Notifications
You must be signed in to change notification settings - Fork 2
feat(tasks): add kanban view for task lists #218
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
Conversation
Add a kanban board view as an alternative to the existing table view for task lists: - Create TaskKanbanView component with 4 columns (To Do, In Progress, Blocked, Done) - Implement multi-container drag-and-drop using @dnd-kit to move tasks between columns - Add view toggle buttons (table/kanban icons) in the toolbar (desktop only) - Extract shared types (TaskItem, STATUS_CONFIG, PRIORITY_CONFIG) to task-list-types.ts - Support creating tasks directly in specific columns via column header + buttons - Dragging tasks between columns automatically updates their status
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughAdds a Kanban board component with dnd-kit drag-and-drop, centralizes task list types/config into a new module, and integrates a view-mode toggle in TaskListView to switch between table and kanban while updating task creation and handler wiring. (≤50 words) Changes
Sequence DiagramsequenceDiagram
participant User
participant Kanban as TaskKanbanView
participant DnD as "dnd-kit\nDragSystem"
participant Handlers as TaskHandlers
participant State
User->>Kanban: start dragging a task card
Kanban->>DnD: onDragStart(activeTask)
DnD-->>Kanban: drag context
Kanban->>State: mark activeTask
User->>Dnd: move over columns/cards
DnD->>Kanban: onDragOver(collision)
Kanban->>State: compute potential targetStatus/position
User->>Dnd: drop
DnD->>Kanban: onDragEnd(dropDetails)
Kanban->>Kanban: compute targetStatus & newPosition
alt Status changed
Kanban->>Handlers: onStatusChange(taskId, newStatus, newPosition)
Handlers->>State: persist change
State->>Kanban: re-render columns
else No change
Kanban->>State: revert order
end
Kanban->>State: clear activeTask, hide overlay
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used📓 Path-based instructions (7)**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.ts📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx,json}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/web/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.tsx📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{tsx,css}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/web/src/components/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (13)📓 Common learnings📚 Learning: 2025-12-22T20:04:40.910ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.966ZApplied to files:
📚 Learning: 2025-12-14T14:54:45.713ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.966ZApplied to files:
📚 Learning: 2025-12-22T20:04:40.910ZApplied to files:
📚 Learning: 2025-12-14T14:54:38.009ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.966ZApplied to files:
📚 Learning: 2025-12-22T20:04:40.910ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.966ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.966ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.966ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.966ZApplied to files:
🧬 Code graph analysis (1)apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (4)
⏰ 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). (2)
🔇 Additional comments (8)
✏️ Tip: You can disable this entire section by setting 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In
`@apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx`:
- Around line 391-394: The handleDragOver callback currently declares an unused
parameter `event` which triggers the pipeline lint error; update the function
signature in TaskKanbanView's handleDragOver to remove the unused parameter
(change from `const handleDragOver = (event: DragOverEvent) => { ... }` to
`const handleDragOver = () => { ... }`) or alternatively rename it to `_event:
DragOverEvent` if you prefer an explicit unused variable, ensuring the body
remains unchanged.
- Around line 338-349: The TaskKanbanView component accepts a pageId prop that
is never used, causing a pipeline failure; fix by either renaming the prop to
_pageId everywhere in the TaskKanbanView signature and TaskKanbanViewProps (to
mark it intentionally unused) or remove pageId from the TaskKanbanViewProps type
and from all call sites that pass it (and update any related handlers or parent
components accordingly) so the prop no longer exists on TaskKanbanView.
- Around line 135-146: The TaskCard component currently declares a driveId prop
that is never used; remove the unused driveId parameter from the TaskCard
function signature and from the corresponding TaskCardProps interface and all
call sites, or if you want to keep it for future use, rename it to _driveId
(prefix with underscore) in the TaskCard signature and TaskCardProps to avoid
the unused-variable pipeline error; update any places that pass driveId to
TaskCard accordingly (either stop passing it or rename the prop there as well).
- Around line 407-418: The variable targetTask in TaskKanbanView is assigned but
never used causing CI failure; either remove the targetTask declaration and
assignment (leave only targetStatus) or rename it to _targetTask to mark
intentional unused scaffolding—update the loop that searches STATUS_ORDER and
tasksByStatus for over.id to stop assigning targetTask (or assign to
_targetTask) so no unused local remains.
🧹 Nitpick comments (2)
apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts (1)
12-13: Consider using the type aliases for consistency.The
statusandpriorityfields inline their union types, butTaskStatusandTaskPrioritytype aliases are defined below. Using the type aliases would ensure consistency and reduce duplication.♻️ Suggested refactor
- status: 'pending' | 'in_progress' | 'completed' | 'blocked'; - priority: 'low' | 'medium' | 'high'; + status: TaskStatus; + priority: TaskPriority;Note: This requires moving the type aliases above the interface or using a forward declaration pattern.
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (1)
64-74: Consider removing unuseddriveIdfrom SortableTaskCardProps too.If
driveIdis removed fromTaskCard, it should also be removed fromSortableTaskCardPropsto maintain consistency.♻️ Suggested cleanup
If removing
driveIdentirely:interface SortableTaskCardProps { task: TaskItem; canEdit: boolean; - driveId: string; handlers: TaskHandlers; isEditing: boolean; editingTitle: string; onEditingTitleChange: (title: string) => void; onCancelEdit: () => void; }And update the component accordingly.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Never useanytypes - 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 withuseprefix), Zustand stores (camelCase withuseprefix), and React components (PascalCase)
Lint with Next/ESLint as configured inapps/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/dbpackage for database access
Use ESM modules throughout the codebase
**/*.{ts,tsx}: Never useanytypes - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.tsapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: React component files should use PascalCase (e.g.,UserProfile.tsx)
Use@dnd-kitfor drag-and-drop functionality
Use Zustand for client state management
Use SWR for server state management and caching
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Format code with Prettier
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.tsapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS and shadcn/ui components for styling and UI
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.tsapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
apps/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/src/components/**/*.{ts,tsx}: When document editing, register editing state withuseEditingStore.getState().startEditing()to prevent UI refreshes, and clean up in return statement
When AI is streaming, register streaming state withuseEditingStore.getState().startStreaming()to prevent UI refreshes, and clean up in return statement
For SWR data fetching with editing protection, useisPaused: () => hasLoadedRef.current && isEditingActive()to allow initial fetch and only pause after, withrevalidateOnFocus: false
Use Zustand for client-side state management as the primary state solution
Use SWR for server state and caching with proper configuration includingrevalidateOnFocus: falsefor editing protection
Use TipTap rich text editor with markdown support for document editing
Use Monaco Editor for code editing features
Use@dnd-kitfor 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/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.tsapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
**/*.ts: React hook files should use camelCase matching the exported hook name (e.g.,useAuth.ts)
Zustand store files should use camelCase withuseprefix (e.g.,useAuthStore.ts)
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
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 dnd-kit for drag-and-drop functionality instead of other libraries
📚 Learning: 2025-12-22T20:04:40.910Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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 dnd-kit for drag-and-drop functionality instead of other libraries
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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/layout/middle-content/page-views/task-list/task-list-types.ts
📚 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} : When document editing, register editing state with `useEditingStore.getState().startEditing()` to prevent UI refreshes, and clean up in return statement
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🧬 Code graph analysis (1)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (2)
apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts (4)
ViewMode(54-54)TaskStatus(52-52)TaskItem(3-39)TaskHandlers(73-83)apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (1)
TaskKanbanView(338-525)
🪛 GitHub Actions: Test Suite
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
[error] 138-138: eslint: @typescript-eslint/no-unused-vars - 'driveId' is defined but never used. Allowed unused args must match /^_/u.
[error] 341-341: eslint: @typescript-eslint/no-unused-vars - 'pageId' is defined but never used. Allowed unused args must match /^_/u.
[error] 391-391: eslint: @typescript-eslint/no-unused-vars - 'event' is defined but never used. Allowed unused args must match /^_/u.
[error] 415-415: eslint: @typescript-eslint/no-unused-vars - 'targetTask' is assigned a value but never used. Allowed unused vars must match /^_/u.
🔇 Additional comments (11)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (5)
69-78: LGTM! Well-organized type imports from centralized module.Good extraction of shared types and configurations to
task-list-types.ts. This improves maintainability and ensures consistency between Table and Kanban views.
422-437: LGTM! Clean signature update supporting both table and Kanban task creation.The optional parameters enable column-specific task creation in Kanban while preserving existing toolbar input behavior.
609-620: LGTM! Clean handler aggregation following the TaskHandlers interface.The
taskHandlersobject provides a clean way to pass all task operations to theTaskKanbanViewcomponent.
680-723: LGTM! Well-implemented view toggle with appropriate mobile restrictions.Desktop-only Kanban view makes sense given horizontal space requirements. The conditional "New Task" button visibility correctly defers to column-level creation in Kanban mode.
779-791: LGTM! Clean conditional rendering with proper prop passing.The
TaskKanbanViewintegration correctly receives all required props including the handlers object and editing state.apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts (2)
73-83: LGTM! Well-defined handler interface.The
TaskHandlersinterface provides a clear contract for task operations. Usingstringfor status/priority parameters aligns with how Select components pass values.
56-70: LGTM! Well-typed configuration constants.The
STATUS_CONFIG,PRIORITY_CONFIG, andSTATUS_ORDERexports provide consistent styling and ordering across views. UsingRecord<TaskStatus, ...>ensures all statuses are covered.apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (4)
76-116: LGTM! Correct dnd-kit sortable wrapper implementation.Good use of
useSortablehook with task data attachment for drag event handling. The separation between sortable logic and card rendering is clean.
149-265: LGTM! Well-structured task card with proper interaction handling.The card correctly handles edit mode, completion toggle, and actions. The hover-based visibility for drag handle and action button provides a clean UX.
305-336: LGTM! Clean inline task creation input.Simple and effective implementation with proper keyboard handling for Enter (submit) and Escape (cancel).
441-524: LGTM! Well-implemented Kanban board with dnd-kit.Correct use of
DndContext,SortableContext, andDragOverlayfor multi-container drag-and-drop. The column structure withScrollAreahandles overflow well.Based on learnings, dnd-kit is the correct library choice for this implementation.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
Show resolved
Hide resolved
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
Show resolved
Hide resolved
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
Outdated
Show resolved
Hide resolved
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
Show resolved
Hide resolved
Prefix unused props and variables with underscore to satisfy ESLint no-unused-vars rule: driveId, pageId, event, and targetTask. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
62bd683 to
894187c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx`:
- Around line 100-106: The TaskCard is being passed an undefined variable
driveId inside the SortableTaskCard render; change the prop to forward the
existing _driveId prop that is in scope instead — replace _driveId={driveId}
with _driveId={_driveId} in the SortableTaskCard/TaskKanbanView render (the JSX
block using setNodeRef, style, TaskCard and handlers) so the component uses the
correct prop name.
- Around line 463-472: TaskKanbanView: empty columns aren't registered as drop
targets because SortableContext has no items, so wrap each column container with
dnd-kit useDroppable; call useDroppable({id: status}) inside the column render,
apply the returned setNodeRef to the column container div (replacing its ref),
and keep data-status and existing className, so even when tasksByStatus[status]
is empty the column is a valid drop target and `over` won't be null.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Never useanytypes - 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 withuseprefix), Zustand stores (camelCase withuseprefix), and React components (PascalCase)
Lint with Next/ESLint as configured inapps/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/dbpackage for database access
Use ESM modules throughout the codebase
**/*.{ts,tsx}: Never useanytypes - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: React component files should use PascalCase (e.g.,UserProfile.tsx)
Use@dnd-kitfor drag-and-drop functionality
Use Zustand for client state management
Use SWR for server state management and caching
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Format code with Prettier
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS and shadcn/ui components for styling and UI
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
apps/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/src/components/**/*.{ts,tsx}: When document editing, register editing state withuseEditingStore.getState().startEditing()to prevent UI refreshes, and clean up in return statement
When AI is streaming, register streaming state withuseEditingStore.getState().startStreaming()to prevent UI refreshes, and clean up in return statement
For SWR data fetching with editing protection, useisPaused: () => hasLoadedRef.current && isEditingActive()to allow initial fetch and only pause after, withrevalidateOnFocus: false
Use Zustand for client-side state management as the primary state solution
Use SWR for server state and caching with proper configuration includingrevalidateOnFocus: falsefor editing protection
Use TipTap rich text editor with markdown support for document editing
Use Monaco Editor for code editing features
Use@dnd-kitfor 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/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
📚 Learning: 2025-12-22T20:04:40.910Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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 dnd-kit for drag-and-drop functionality instead of other libraries
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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} : When document editing, register editing state with `useEditingStore.getState().startEditing()` to prevent UI refreshes, and clean up in return statement
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🧬 Code graph analysis (2)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (1)
apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts (5)
TaskItem(3-39)TaskHandlers(73-83)TaskStatus(52-52)STATUS_CONFIG(56-61)STATUS_ORDER(70-70)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (2)
apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts (6)
ViewMode(54-54)TaskStatus(52-52)TaskItem(3-39)TaskHandlers(73-83)STATUS_CONFIG(56-61)PRIORITY_CONFIG(63-67)apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (1)
TaskKanbanView(338-525)
⏰ 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). (2)
- GitHub Check: Unit Tests
- GitHub Check: Lint & TypeScript Check
🔇 Additional comments (3)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (1)
305-333: Inline task creation flow looks solid.The blur/Enter/Escape handling is tight and matches expected UX for quick creation.
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (2)
422-433: Optional-status task creation is cleanly integrated.The new
statusparameter support is minimal and preserves existing table behavior.
680-791: View toggle + Kanban wiring is clear and cohesive.The desktop toggle and the TaskKanbanView handoff via
taskHandlersare well-structured and easy to follow.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
Show resolved
Hide resolved
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx`:
- Around line 683-706: The two icon-only toggle buttons for changing viewMode
(the button that calls setViewMode('table') rendering <LayoutList /> and the
button that calls setViewMode('kanban') rendering <Kanban />) lack aria-label
attributes, so screen readers may not announce their purpose; add appropriate
aria-labels (e.g., aria-label="Table view" and aria-label="Kanban view") to
those buttons while keeping the existing title and className/cn logic intact so
functionality and styling are unchanged.
- Around line 422-433: handleCreateTask trims only newTaskTitle but not the
optional title param, allowing whitespace-only titles from the Kanban input to
pass validation; fix by normalizing both inputs at start: compute a single
trimmedTitle = (title ?? newTaskTitle).trim(), use trimmedTitle for the empty
check, for the post body (title: trimmedTitle), and when clearing input (if no
title param then setNewTaskTitle('')); keep the status spread logic as-is.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Never useanytypes - 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 withuseprefix), Zustand stores (camelCase withuseprefix), and React components (PascalCase)
Lint with Next/ESLint as configured inapps/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/dbpackage for database access
Use ESM modules throughout the codebase
**/*.{ts,tsx}: Never useanytypes - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: React component files should use PascalCase (e.g.,UserProfile.tsx)
Use@dnd-kitfor drag-and-drop functionality
Use Zustand for client state management
Use SWR for server state management and caching
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Format code with Prettier
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS and shadcn/ui components for styling and UI
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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/layout/middle-content/page-views/task-list/TaskListView.tsx
apps/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/src/components/**/*.{ts,tsx}: When document editing, register editing state withuseEditingStore.getState().startEditing()to prevent UI refreshes, and clean up in return statement
When AI is streaming, register streaming state withuseEditingStore.getState().startStreaming()to prevent UI refreshes, and clean up in return statement
For SWR data fetching with editing protection, useisPaused: () => hasLoadedRef.current && isEditingActive()to allow initial fetch and only pause after, withrevalidateOnFocus: false
Use Zustand for client-side state management as the primary state solution
Use SWR for server state and caching with proper configuration includingrevalidateOnFocus: falsefor editing protection
Use TipTap rich text editor with markdown support for document editing
Use Monaco Editor for code editing features
Use@dnd-kitfor 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/layout/middle-content/page-views/task-list/TaskListView.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
📚 Learning: 2025-12-22T20:04:40.910Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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 dnd-kit for drag-and-drop functionality instead of other libraries
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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} : When document editing, register editing state with `useEditingStore.getState().startEditing()` to prevent UI refreshes, and clean up in return statement
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🧬 Code graph analysis (1)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (2)
apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts (6)
ViewMode(54-54)TaskStatus(52-52)TaskItem(3-39)TaskHandlers(73-83)STATUS_CONFIG(56-61)PRIORITY_CONFIG(63-67)apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (1)
TaskKanbanView(338-525)
🔇 Additional comments (1)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (1)
48-50: Kanban integration wiring looks solid.View-mode state, handler consolidation, and the conditional render path are clean and easy to follow. Nice separation between table and kanban flows.
Also applies to: 69-78, 335-335, 602-620, 709-721, 777-995
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
Show resolved
Hide resolved
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
Show resolved
Hide resolved
Code reviewFound 1 issue:
PageSpace/apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx Lines 420 to 430 in 894187c
To fix, wrap each column container with const KanbanColumn = ({ status, children }) => {
const { setNodeRef } = useDroppable({ id: status });
return <div ref={setNodeRef}>{children}</div>;
};🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
- Import proper @dnd-kit types (DraggableAttributes, SyntheticListenerMap) - Update dragHandleProps interface to use correct types - Remove unnecessary type assertion in drag handle button - Add hasLoadedRef pattern for SWR refresh protection per CLAUDE.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx`:
- Around line 465-495: The column stops accepting drops when empty because empty
columns aren't registered as droppables; fix this in TaskKanbanView by adding a
KanbanColumn wrapper that uses useDroppable({ id: status }) (referencing
useDroppable, setNodeRef, isOver) and wrapping the existing column content (the
div with data-status and classes) so each column is always a registered
droppable; update SortableContext usage to keep items mapping as-is but replace
the column container with KanbanColumn so over can resolve empty columns (also
ensure STATUS_ORDER and over checks still use the status id).
♻️ Duplicate comments (2)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (2)
425-440: Trim kanban-provided titles before validation.When
titleis passed from the Kanban input, it bypasses the.trim()call, potentially allowing whitespace-only titles to pass validation.🔧 Suggested fix
const handleCreateTask = async (title?: string, status?: TaskStatus) => { - const taskTitle = title || newTaskTitle.trim(); + const taskTitle = (title ?? newTaskTitle).trim(); if (!taskTitle || !canEdit) return;
685-710: Add aria-labels to icon-only view toggle buttons.The icon-only buttons have
titleattributes but lackaria-labelfor screen reader accessibility.titleisn't consistently announced by assistive technologies.🔧 Suggested fix
<button onClick={() => setViewMode('table')} className={cn( 'p-1.5 rounded transition-colors', viewMode === 'table' ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground' )} title="Table view" + aria-label="Table view" > <LayoutList className="h-4 w-4" /> </button> <button onClick={() => setViewMode('kanban')} className={cn( 'p-1.5 rounded transition-colors', viewMode === 'kanban' ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground' )} title="Kanban view" + aria-label="Kanban view" > <Kanban className="h-4 w-4" /> </button>
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Never useanytypes - 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 withuseprefix), Zustand stores (camelCase withuseprefix), and React components (PascalCase)
Lint with Next/ESLint as configured inapps/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/dbpackage for database access
Use ESM modules throughout the codebase
**/*.{ts,tsx}: Never useanytypes - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: React component files should use PascalCase (e.g.,UserProfile.tsx)
Use@dnd-kitfor drag-and-drop functionality
Use Zustand for client state management
Use SWR for server state management and caching
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Format code with Prettier
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS and shadcn/ui components for styling and UI
Files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.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/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
apps/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/src/components/**/*.{ts,tsx}: When document editing, register editing state withuseEditingStore.getState().startEditing()to prevent UI refreshes, and clean up in return statement
When AI is streaming, register streaming state withuseEditingStore.getState().startStreaming()to prevent UI refreshes, and clean up in return statement
For SWR data fetching with editing protection, useisPaused: () => hasLoadedRef.current && isEditingActive()to allow initial fetch and only pause after, withrevalidateOnFocus: false
Use Zustand for client-side state management as the primary state solution
Use SWR for server state and caching with proper configuration includingrevalidateOnFocus: falsefor editing protection
Use TipTap rich text editor with markdown support for document editing
Use Monaco Editor for code editing features
Use@dnd-kitfor 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/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
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 dnd-kit for drag-and-drop functionality instead of other libraries
📚 Learning: 2025-12-22T20:04:40.910Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T20:04:40.910Z
Learning: Applies to **/*.tsx : Use dnd-kit for drag-and-drop functionality
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.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 dnd-kit for drag-and-drop functionality instead of other libraries
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsxapps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.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} : When document editing, register editing state with `useEditingStore.getState().startEditing()` to prevent UI refreshes, and clean up in return statement
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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} : For SWR data fetching with editing protection, use `isPaused: () => hasLoadedRef.current && isEditingActive()` to allow initial fetch and only pause after, with `revalidateOnFocus: false`
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.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 SWR for server state and caching with proper configuration including `revalidateOnFocus: false` for editing protection
Applied to files:
apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx
🧬 Code graph analysis (1)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (1)
apps/web/src/components/layout/middle-content/page-views/task-list/task-list-types.ts (5)
TaskItem(3-39)TaskStatus(52-52)PRIORITY_CONFIG(63-67)STATUS_CONFIG(56-61)STATUS_ORDER(70-70)
⏰ 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). (2)
- GitHub Check: Unit Tests
- GitHub Check: Lint & TypeScript Check
🔇 Additional comments (9)
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx (5)
1-22: LGTM! Proper dnd-kit imports and setup.The imports correctly use
@dnd-kit/corefor the drag-and-drop context and@dnd-kit/sortablefor sortable items, following the project's established pattern for drag-and-drop functionality. As per learnings, dnd-kit is the required library for this functionality.
78-118: LGTM! SortableTaskCard correctly implements useSortable.The component properly extracts
attributes,listeners,setNodeRef,transform,transition, andisDraggingfromuseSortable, applies the transform style, and passes drag handle props to TaskCard for controlled dragging.
137-267: LGTM! TaskCard component is well-structured.The card correctly handles:
- Drag handle with proper cursor states
- Checkbox for completion toggle
- Inline title editing with blur/Enter/Escape handlers
- Dropdown menu with conditional "Open" action
- Metadata display (priority, assignee, due date)
307-338: LGTM! NewTaskInput handles input correctly.The component properly trims titles before submission on both Enter and blur, and correctly handles cancellation via Escape. The blur handler appropriately submits valid titles before closing.
509-525: LGTM! DragOverlay correctly renders the dragged card preview.The overlay appropriately renders a non-interactive copy of the task card with
canEdit={false}andisDraggingvisual state.apps/web/src/components/layout/middle-content/page-views/task-list/TaskListView.tsx (4)
356-367: LGTM! SWR configuration follows the editing protection pattern.The SWR setup correctly implements the
hasLoadedRefpattern:isPausedonly activates after initial load (hasLoadedRef.current && isAnyActive), andonSuccesssets the flag. Combined withrevalidateOnFocus: false, this properly protects editing state while allowing initial data fetch. As per coding guidelines, this is the correct pattern for SWR with editing protection.
612-623: LGTM! Handler consolidation is clean and type-safe.The
taskHandlersobject properly aggregates all task manipulation callbacks matching theTaskHandlersinterface, enabling clean prop passing toTaskKanbanView.
782-794: LGTM! TaskKanbanView integration is complete.All required props are correctly passed including tasks, permissions, handlers object, editing state, and the create task callback for per-column creation.
796-998: LGTM! Table view rendering preserved correctly.The table view maintains proper structure with
DndContext→SortableContext→SortableTaskRowhierarchy. The new task input row is correctly placed outsideSortableContextto prevent it from being a drag target.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
apps/web/src/components/layout/middle-content/page-views/task-list/TaskKanbanView.tsx
Show resolved
Hide resolved
- Add useDroppable wrapper for kanban columns to accept drops on empty columns - Fix title trimming to handle whitespace-only kanban input - Add aria-labels to view toggle buttons for accessibility Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
All review feedback has been addressed in commit 4b99f37:
Earlier commits (62bd683, 894187c) already addressed the unused variable warnings with underscore prefixes. All CI checks are now passing. |
- Add taskListViewMode to useLayoutStore with Zustand persist middleware - Store preference in localStorage for persistence across page refreshes - Replace local useState with store selectors in TaskListView Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a kanban board view as an alternative to the existing table view for task lists:
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.