Skip to content

Add task statuses #3057

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

Merged
merged 2 commits into from
Jun 8, 2025
Merged

Add task statuses #3057

merged 2 commits into from
Jun 8, 2025

Conversation

vhpx
Copy link
Member

@vhpx vhpx commented Jun 8, 2025

Summary by CodeRabbit

  • New Features

    • Introduced customizable task board workflows with status templates, allowing boards to be created from predefined or custom status sets.
    • Added new board views, including a "status-grouped" view, alongside enhanced Kanban and list views.
    • Enhanced task lists with status, color, and position, supporting drag-and-drop reordering and inline editing.
    • Improved task cards with inline editing, priority management, due date shortcuts, and deletion with confirmation.
    • Added rich board statistics, workflow template previews, and improved board creation with template selection.
  • Bug Fixes

    • Improved state handling and UI feedback for loading, searching, and empty states in task lists and boards.
  • Refactor

    • Streamlined component props and internal state management for better performance and maintainability.
    • Updated data models to support new status and template features.
  • Chores

    • Enhanced database schema and API types to support board status templates, list statuses, and improved ordering.
    • Standardized function argument and return type ordering for consistency.
  • Style

    • Refined UI spacing, color coding, and visual feedback for board, list, and task components.

@vhpx vhpx self-assigned this Jun 8, 2025
Copy link
Contributor

coderabbitai bot commented Jun 8, 2025

Walkthrough

This update introduces a comprehensive task board status system, including database migrations for status enums, templates, and enhanced task list metadata. The frontend is refactored to support new status-based workflows, including new board views (status-grouped), interactive drag-and-drop for lists and tasks, inline editing, and template-driven board creation. Types and API utilities are expanded accordingly.

Changes

Files / Group Change Summary
apps/db/supabase/migrations/...add_task_statuses.sql Adds enum task_board_status, table task_board_status_templates, alters task_lists and workspace_boards with status/template fields, triggers for status enforcement, RLS, and default data migrations.
packages/types/src/primitives/TaskBoard.ts
packages/types/src/supabase.ts
Adds types/interfaces for task board statuses, templates, and extends task list/board/task types; updates Supabase types for new tables, fields, and enums; reorders function arguments for consistency.
apps/web/src/lib/task-helper.ts Enhances moveTask with status logic and logging; adds functions/hooks for status templates, board creation from template, task list status management, and list reordering.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx Refactors props to accept full board object; adds statistics, inline editing, confirmation dialogs, improved view switcher, and UI restructuring.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx Adds 'status-grouped' view; removes realtime subscriptions; refactors view switching and header; inserts BoardSummary.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx Refactors to take board prop; memoizes filtering/sorting; adds helpers for rendering status, priority, and dates; improves loading and empty states.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-summary.tsx Reduces CSS grid gap.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-client.tsx Removes BoardSummary import and usage.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/kanban.tsx Updates DnD sensors, column sorting by status/position, uses full TaskList objects, improves loading UI, and data invalidation logic.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list.tsx Extends Column to TaskList, adds color/status mappings, updates UI for color/status, and improves empty state handling.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task.tsx Adds inline editing, delete dialog, quick priority/due date actions, dynamic color styling, and UI/UX enhancements.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list-form.tsx Supports status/color on creation, inline/legacy modes, cancel callback, and improved error handling/UI.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-actions.tsx Fixes dialog state management and query enable condition.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/form.tsx Adds template selection, board creation with templates, previews, loading skeletons, and improved UI/UX.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/page.tsx Adds requireExpansion prop to FeatureSummary.
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/enhanced-task-list.tsx
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/status-grouped-board.tsx
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/status-section.tsx
Adds new components for enhanced task lists, status-grouped board view, and status sections with DnD, editing, and creation features.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant BoardForm
    participant StatusTemplates
    participant Supabase
    participant BoardView

    User->>BoardForm: Open create board dialog
    BoardForm->>StatusTemplates: Fetch available templates
    StatusTemplates-->>BoardForm: Return templates
    User->>BoardForm: Select template & submit
    BoardForm->>Supabase: Create board with template_id
    Supabase-->>BoardForm: Board created, lists auto-generated via trigger
    BoardForm-->>BoardView: Show new board with lists by status
Loading
sequenceDiagram
    participant User
    participant BoardView
    participant EnhancedTaskList
    participant Supabase

    User->>BoardView: Drag task to new list/status
    BoardView->>EnhancedTaskList: onDragEnd
    EnhancedTaskList->>Supabase: Update task list/status, archive if needed
    Supabase-->>EnhancedTaskList: Success/failure
    EnhancedTaskList-->>BoardView: Invalidate queries, update UI
Loading

Suggested labels

nova

Poem

🐇
A hop, a skip, a status new,
Boards with colors, workflows grew!
Drag your lists, your tasks align,
Templates guide and stats now shine.
With every click and every hue,
The rabbit cheers this leap for you!
🥕✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx

Oops! Something went wrong! :(

ESLint: 9.28.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@typescript-eslint/parser' imported from /eslint.config.mjs
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:255:9)
at packageResolve (node:internal/modules/esm/resolve:767:81)
at moduleResolve (node:internal/modules/esm/resolve:853:18)
at defaultResolve (node:internal/modules/esm/resolve:983:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:799:12)
at #cachedDefaultResolve (node:internal/modules/esm/loader:723:25)
at ModuleLoader.resolve (node:internal/modules/esm/loader:706:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:307:38)
at #link (node:internal/modules/esm/module_job:170:49)

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-summary.tsx

Oops! Something went wrong! :(

ESLint: 9.28.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@typescript-eslint/parser' imported from /eslint.config.mjs
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:255:9)
at packageResolve (node:internal/modules/esm/resolve:767:81)
at moduleResolve (node:internal/modules/esm/resolve:853:18)
at defaultResolve (node:internal/modules/esm/resolve:983:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:799:12)
at #cachedDefaultResolve (node:internal/modules/esm/loader:723:25)
at ModuleLoader.resolve (node:internal/modules/esm/loader:706:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:307:38)
at #link (node:internal/modules/esm/module_job:170:49)

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/kanban.tsx

Oops! Something went wrong! :(

ESLint: 9.28.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@typescript-eslint/parser' imported from /eslint.config.mjs
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:255:9)
at packageResolve (node:internal/modules/esm/resolve:767:81)
at moduleResolve (node:internal/modules/esm/resolve:853:18)
at defaultResolve (node:internal/modules/esm/resolve:983:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:799:12)
at #cachedDefaultResolve (node:internal/modules/esm/loader:723:25)
at ModuleLoader.resolve (node:internal/modules/esm/loader:706:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:307:38)
at #link (node:internal/modules/esm/module_job:170:49)

  • 14 others
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

graphite-app bot commented Jun 8, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

Copy link

codecov bot commented Jun 8, 2025

Codecov Report

Attention: Patch coverage is 0.03028% with 3302 lines in your changes missing coverage. Please review.

Project coverage is 0.84%. Comparing base (a0f68ec) to head (aca769e).
Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
...(dashboard)/[wsId]/tasks/boards/[boardId]/task.tsx 0.00% 610 Missing ⚠️
[...sId]/tasks/boards/[boardId]/enhanced-task-list.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/3057?src=pr&el=tree&filepath=apps%2Fweb%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%5BwsId%5D%2Ftasks%2Fboards%2F%5BboardId%5D%2Fenhanced-task-list.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy93ZWIvc3JjL2FwcC9bbG9jYWxlXS8oZGFzaGJvYXJkKS9bd3NJZF0vdGFza3MvYm9hcmRzL1tib2FyZElkXS9lbmhhbmNlZC10YXNrLWxpc3QudHN4) 0.00% 472 Missing and 1 partial ⚠️
[...d]/tasks/boards/[boardId]/status-grouped-board.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/3057?src=pr&el=tree&filepath=apps%2Fweb%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%5BwsId%5D%2Ftasks%2Fboards%2F%5BboardId%5D%2Fstatus-grouped-board.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy93ZWIvc3JjL2FwcC9bbG9jYWxlXS8oZGFzaGJvYXJkKS9bd3NJZF0vdGFza3MvYm9hcmRzL1tib2FyZElkXS9zdGF0dXMtZ3JvdXBlZC1ib2FyZC50c3g=) 0.00% 442 Missing and 1 partial ⚠️
[...]/tasks/boards/[boardId]/_components/list-view.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/3057?src=pr&el=tree&filepath=apps%2Fweb%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%5BwsId%5D%2Ftasks%2Fboards%2F%5BboardId%5D%2F_components%2Flist-view.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy93ZWIvc3JjL2FwcC9bbG9jYWxlXS8oZGFzaGJvYXJkKS9bd3NJZF0vdGFza3MvYm9hcmRzL1tib2FyZElkXS9fY29tcG9uZW50cy9saXN0LXZpZXcudHN4) 0.00% 402 Missing ⚠️
.../[locale]/(dashboard)/[wsId]/tasks/boards/form.tsx 0.00% 368 Missing ⚠️
...asks/boards/[boardId]/_components/board-header.tsx 0.00% 282 Missing and 1 partial ⚠️
apps/web/src/lib/task-helper.ts 0.00% 209 Missing and 1 partial ⚠️
...)/[wsId]/tasks/boards/[boardId]/status-section.tsx 0.00% 208 Missing and 1 partial ⚠️
...ashboard)/[wsId]/tasks/boards/[boardId]/kanban.tsx 0.00% 85 Missing ⚠️
...)/[wsId]/tasks/boards/[boardId]/task-list-form.tsx 0.00% 84 Missing ⚠️
... and 6 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3057      +/-   ##
==========================================
- Coverage    0.85%    0.84%   -0.01%     
==========================================
  Files        2466     2469       +3     
  Lines      298841   301482    +2641     
  Branches     2967     2970       +3     
==========================================
  Hits         2546     2546              
- Misses     294160   296798    +2638     
- Partials     2135     2138       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vhpx vhpx marked this pull request as ready for review June 8, 2025 17:17
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🔭 Outside diff range comments (1)
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx (1)

113-124: ⚠️ Potential issue

Enhance delete error handling and cache invalidation

The delete function should provide user feedback on errors and invalidate relevant queries for consistency.

 async function handleDelete() {
   try {
     setIsLoading(true);
     const supabase = createClient();
-    await supabase.from('workspace_boards').delete().eq('id', board.id);
+    const { error } = await supabase
+      .from('workspace_boards')
+      .delete()
+      .eq('id', board.id);
+    
+    if (error) throw error;
+    
+    // Invalidate workspace boards list
+    queryClient.invalidateQueries({ queryKey: ['workspace-boards'] });
     router.push('../');
   } catch (error) {
     console.error('Failed to delete board:', error);
+    toast({
+      title: 'Failed to delete board',
+      description: error instanceof Error ? error.message : 'Please try again',
+      variant: 'destructive',
+    });
   } finally {
     setIsLoading(false);
   }
 }
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 117-117: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L117
Added line #L117 was not covered by tests

🧹 Nitpick comments (21)
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-summary.tsx (1)

137-137: Spacing adjustment looks good.

The reduced gap provides a more compact layout for the board summary cards.

Note: Static analysis indicates this line isn't covered by tests, though CSS changes typically don't require direct test coverage.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 137-137: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-summary.tsx#L137
Added line #L137 was not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/enhanced-task-list.tsx (2)

76-81: Consider using icon components instead of emojis for better cross-platform consistency.

Emojis may render differently across platforms and browsers, potentially causing UI inconsistencies. Consider using icon components from your UI library for better control and accessibility.

-const statusIcons = {
-  not_started: '⚪',
-  active: '🔵',
-  done: '🟢',
-  closed: '🟣',
-};
+import { Circle, CircleCheck, CircleDot, CircleX } from '@tuturuuu/ui/icons';
+
+const statusIcons = {
+  not_started: <Circle className="h-4 w-4 text-gray-400" />,
+  active: <CircleDot className="h-4 w-4 text-blue-500" />,
+  done: <CircleCheck className="h-4 w-4 text-green-500" />,
+  closed: <CircleX className="h-4 w-4 text-purple-500" />,
+};

370-393: Extract inline SVG to a reusable icon component.

The inline SVG for the hidden tasks indicator should be extracted to maintain consistency with other icons and improve code organization.

Create a new icon component:

// In your icons directory
export const EyeOff = ({ className, ...props }) => (
  <svg
    className={className}
    fill="none"
    stroke="currentColor"
    viewBox="0 0 24 24"
    {...props}
  >
    <path
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth={2}
      d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L8.465 8.465m1.413 1.413L18.75 18.75m-7.036-7.036L12 12m-1.036-1.036L9.465 9.465m9.193 9.193L20.75 20.75M4.222 4.222l16.556 16.556"
    />
  </svg>
);

Then use it in the component:

-<svg
-  className="h-6 w-6 text-dynamic-purple/60"
-  fill="none"
-  stroke="currentColor"
-  viewBox="0 0 24 24"
->
-  <path
-    strokeLinecap="round"
-    strokeLinejoin="round"
-    strokeWidth={2}
-    d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L8.465 8.465m1.413 1.413L18.75 18.75m-7.036-7.036L12 12m-1.036-1.036L9.465 9.465m9.193 9.193L20.75 20.75M4.222 4.222l16.556 16.556"
-  />
-</svg>
+<EyeOff className="h-6 w-6 text-dynamic-purple/60" />
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/status-grouped-board.tsx (3)

36-50: Document the default value for hideTasksMode in the interface.

The hideTasksMode prop defaults to true but this isn't clear from the interface definition. Consider adding JSDoc or adjusting the type definition for clarity.

 interface Props {
   lists: TaskList[];
   tasks: Task[];
   boardId: string;
   onUpdate: () => void;
+  /** Whether to hide individual tasks (defaults to true) */
   hideTasksMode?: boolean;
 }

154-205: Add documentation for the optimistic update strategy.

The optimistic updates improve UX but the strategy should be documented for maintainability.

Add a comment before the function:

+  /**
+   * Handles drag over events with optimistic updates for immediate visual feedback.
+   * Updates are reverted in onDragEnd if the operation is cancelled or fails.
+   */
   function onDragOver(event: DragOverEvent) {

346-358: Extract inline SVG to maintain consistency.

Similar to the previous file, this inline SVG should be extracted to a reusable component.

Create an icon component for the board structure icon and import it instead of using inline SVG.

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx (2)

26-28: Remove unnecessary comment.

The comment about the Supabase client adds no value and should be removed.

   const handleUpdate = async () => {
-    // const supabase = createClient(); // Not needed for current implementation
-
     // Refresh both tasks and lists
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 26-27: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L26-L27
Added lines #L26 - L27 were not covered by tests


36-69: Eliminate duplicate code in the switch statement.

The default case duplicates the 'status-grouped' case. Use fall-through to avoid repetition.

   const renderView = () => {
     switch (currentView) {
       case 'status-grouped':
-        return (
-          <StatusGroupedBoard
-            lists={board.lists}
-            tasks={board.tasks}
-            boardId={board.id}
-            onUpdate={handleUpdate}
-            hideTasksMode={true}
-          />
-        );
-      case 'kanban':
-        return (
-          <KanbanBoard
-            boardId={board.id}
-            tasks={board.tasks}
-            isLoading={false}
-          />
-        );
-      case 'list':
-        return <ListView board={board} />;
       default:
         return (
           <StatusGroupedBoard
             lists={board.lists}
             tasks={board.tasks}
             boardId={board.id}
             onUpdate={handleUpdate}
             hideTasksMode={true}
           />
         );
+      case 'kanban':
+        return (
+          <KanbanBoard
+            boardId={board.id}
+            tasks={board.tasks}
+            isLoading={false}
+          />
+        );
+      case 'list':
+        return <ListView board={board} />;
     }
   };
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 36-69: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L36-L69
Added lines #L36 - L69 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list.tsx (1)

40-45: Consider using proper icons for better accessibility

While emojis work, consider using proper SVG icons from your icon library for better accessibility, consistency, and professional appearance. Icons would also scale better and support theming.

Example implementation:

-const statusIcons = {
-  not_started: '⚪',
-  active: '🔵',
-  done: '🟢',
-  closed: '🟣',
-};
+import { Circle, PlayCircle, CheckCircle2, XCircle } from '@tuturuuu/ui/icons';
+
+const statusIcons = {
+  not_started: Circle,
+  active: PlayCircle,
+  done: CheckCircle2,
+  closed: XCircle,
+};

Then update the usage:

-<span className="text-sm">{statusIcon}</span>
+{(() => {
+  const Icon = statusIcons[column.status] || Circle;
+  return <Icon className="h-4 w-4 text-muted-foreground" />;
+})()}
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/form.tsx (3)

37-39: Remove unnecessary ESLint disable comment

The onFinish parameter is actually used in the component (lines 104, 120), so the ESLint disable comment is unnecessary.

-  // eslint-disable-next-line no-unused-vars
   onFinish?: (data: z.infer<typeof FormSchema>) => void;

47-52: Consider making template icons more flexible

The templateIcons mapping uses hardcoded template names, which could break if template names change in the database. Consider using a more flexible approach.

-const templateIcons = {
-  'Basic Kanban': Crown,
-  'Software Development': Users,
-  'Content Creation': FileText,
-  'Sales Pipeline': TrendingUp,
-};
+const templateIcons: Record<string, typeof Crown> = {
+  'Basic Kanban': Crown,
+  'Software Development': Users,
+  'Content Creation': FileText,
+  'Sales Pipeline': TrendingUp,
+};
+
+// Or better, include icon type in template data from backend

91-132: Consider migrating edit functionality to React Query

The form uses React Query mutation for creating boards but legacy fetch API for editing. Consider creating a useUpdateBoard mutation hook for consistency and better error handling.

This would provide consistent error handling, loading states, and cache invalidation across both operations. Would you like me to help create the useUpdateBoard mutation hook?

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx (1)

65-87: Optimize statistics calculation with single iteration

The current implementation iterates through tasks multiple times. Consider calculating all statistics in a single pass for better performance, especially with large task lists.

 const stats = useMemo(() => {
   const totalTasks = board.tasks.length;
   const totalLists = board.lists.length;
-  const completedTasks = board.tasks.filter((task) => {
-    const taskList = board.lists.find((list) => list.id === task.list_id);
-    return taskList?.status === 'done' || taskList?.status === 'closed';
-  }).length;
-  const activeTasks = board.tasks.filter((task) => {
-    const taskList = board.lists.find((list) => list.id === task.list_id);
-    return taskList?.status === 'active';
-  }).length;
+  
+  // Create a map for O(1) list lookups
+  const listMap = new Map(board.lists.map(list => [list.id, list]));
+  
+  // Single pass through tasks
+  let completedTasks = 0;
+  let activeTasks = 0;
+  
+  board.tasks.forEach(task => {
+    const taskList = listMap.get(task.list_id);
+    if (taskList?.status === 'done' || taskList?.status === 'closed') {
+      completedTasks++;
+    } else if (taskList?.status === 'active') {
+      activeTasks++;
+    }
+  });
+  
   const completionRate =
     totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;

   return {
     totalTasks,
     totalLists,
     completedTasks,
     activeTasks,
     completionRate,
   };
 }, [board.tasks, board.lists]);
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 65-112: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L65-L112
Added lines #L65 - L112 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list-form.tsx (1)

55-68: Remove redundant default case for better type safety.

Since all values of TaskBoardStatus are explicitly handled, the default case is unnecessary and prevents TypeScript from catching missing cases if new statuses are added.

 function getDefaultColorForStatus(status: TaskBoardStatus): SupportedColor {
   switch (status) {
     case 'not_started':
       return 'GRAY';
     case 'active':
       return 'BLUE';
     case 'done':
       return 'GREEN';
     case 'closed':
       return 'PURPLE';
-    default:
-      return 'GRAY';
   }
 }
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx (2)

208-247: Extract priority configuration to reduce render overhead.

The priorityConfig object is recreated on every render. Extract it as a module-level constant for better performance.

Move the configuration outside the component:

+const PRIORITY_CONFIG = {
+  1: {
+    label: 'High',
+    color: 'text-dynamic-red/80',
+    bgColor: 'bg-dynamic-red/10',
+    borderColor: 'border-dynamic-red/30',
+  },
+  2: {
+    label: 'Medium',
+    color: 'text-dynamic-yellow/80',
+    bgColor: 'bg-dynamic-yellow/10',
+    borderColor: 'border-dynamic-yellow/30',
+  },
+  3: {
+    label: 'Low',
+    color: 'text-dynamic-green/80',
+    bgColor: 'bg-dynamic-green/10',
+    borderColor: 'border-dynamic-green/30',
+  },
+} as const;

 export function ListView({ board }: Props) {
   // ... component code ...
   
   function renderPriority(priority: number) {
-    const priorityConfig = {
-      1: { /* ... */ },
-      2: { /* ... */ },
-      3: { /* ... */ },
-    };
-
-    const config = priorityConfig[priority as keyof typeof priorityConfig];
+    const config = PRIORITY_CONFIG[priority as keyof typeof PRIORITY_CONFIG];
     if (!config) return null;

249-276: Extract date status configuration for performance.

Similar to the priority configuration, the statusConfig object is recreated on every call.

Extract as a constant:

+const DATE_STATUS_CONFIG = {
+  overdue: { color: 'text-dynamic-red/80', icon: AlertTriangle },
+  today: { color: 'text-dynamic-blue/80', icon: Clock },
+  upcoming: { color: 'text-muted-foreground', icon: Calendar },
+  completed: { color: 'text-muted-foreground', icon: Calendar },
+} as const;

 function renderDateCell(date: string | null, isEndDate = false) {
   if (!date) return null;
   
   const status = getDateStatus(date, false);
   const formattedDate = formatDate(date);
   
-  const statusConfig = {
-    overdue: { color: 'text-dynamic-red/80', icon: AlertTriangle },
-    today: { color: 'text-dynamic-blue/80', icon: Clock },
-    upcoming: { color: 'text-muted-foreground', icon: Calendar },
-    completed: { color: 'text-muted-foreground', icon: Calendar },
-  };
-
-  const config = statusConfig[status];
+  const config = DATE_STATUS_CONFIG[status];
   const Icon = config.icon;
apps/db/supabase/migrations/20250608140008_add_task_statuses.sql (1)

191-198: Ensure users are informed about automatic task archival.

This migration automatically archives all tasks in lists with 'done' or 'closed' status. While logical, this could be unexpected behavior for existing users.

Consider adding a migration note or changelog entry to inform users about this automatic archival behavior. You might also want to add a comment in the migration explaining the rationale.

apps/web/src/lib/task-helper.ts (3)

151-151: Remove console.log statements before production deployment.

The extensive console logging added for debugging should be removed or wrapped in a debug flag to avoid cluttering production logs.

Consider using a debug flag:

-  console.log('🔄 Starting moveTask:', { taskId, newListId });
+  if (process.env.NODE_ENV === 'development') {
+    console.log('🔄 Starting moveTask:', { taskId, newListId });
+  }

Also applies to: 161-161, 165-165, 171-174, 198-198, 202-206


487-491: Remove console.log statements from mutation hook.

Similar to the moveTask function, these debug logs should be removed or conditionally enabled.

Also applies to: 496-497, 518-519, 533-534, 547-548


685-685: Consider increasing staleTime for relatively static data.

Status templates are unlikely to change frequently. Consider increasing the staleTime to reduce unnecessary refetches.

-    staleTime: 10 * 60 * 1000, // 10 minutes
+    staleTime: 60 * 60 * 1000, // 1 hour
packages/types/src/supabase.ts (1)

3477-3477: Consider adding type safety for the statuses field.

The statuses field uses a generic Json type, which doesn't provide compile-time type safety. Consider defining a specific interface for the status structure to ensure consistency across templates.

You could define a more specific type for the statuses field:

type StatusDefinition = {
  id: string;
  name: string;
  color?: string;
  position: number;
  type: 'not_started' | 'active' | 'done' | 'closed';
};

// Then use: statuses: StatusDefinition[];
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95f4bda and aca769e.

📒 Files selected for processing (19)
  • apps/db/supabase/migrations/20250608140008_add_task_statuses.sql (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-client.tsx (0 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx (2 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-summary.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx (8 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/enhanced-task-list.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/kanban.tsx (6 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/status-grouped-board.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/status-section.tsx (1 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-actions.tsx (2 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list-form.tsx (2 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list.tsx (5 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task.tsx (6 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/form.tsx (2 hunks)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/page.tsx (1 hunks)
  • apps/web/src/lib/task-helper.ts (8 hunks)
  • packages/types/src/primitives/TaskBoard.ts (4 hunks)
  • packages/types/src/supabase.ts (23 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-client.tsx
🧰 Additional context used
🧬 Code Graph Analysis (4)
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list-form.tsx (1)
packages/types/src/primitives/TaskBoard.ts (1)
  • TaskBoardStatus (3-3)
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/form.tsx (5)
packages/types/src/primitives/TaskBoard.ts (1)
  • TaskBoard (22-32)
apps/web/src/lib/task-helper.ts (2)
  • useStatusTemplates (678-687)
  • useCreateBoardWithTemplate (689-719)
packages/ui/src/components/ui/sonner.tsx (1)
  • toast (29-29)
packages/ui/src/components/ui/form.tsx (6)
  • Form (181-181)
  • FormField (184-184)
  • FormItem (185-185)
  • FormLabel (186-186)
  • FormControl (182-182)
  • FormMessage (187-187)
packages/ui/src/components/ui/badge.tsx (1)
  • Badge (49-49)
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx (4)
packages/types/src/primitives/TaskBoard.ts (3)
  • TaskBoard (22-32)
  • Task (48-65)
  • TaskList (34-46)
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task.tsx (1)
  • Task (60-60)
packages/ui/src/components/ui/badge.tsx (1)
  • Badge (49-49)
packages/ui/src/components/ui/dropdown-menu.tsx (4)
  • DropdownMenu (241-241)
  • DropdownMenuTrigger (255-255)
  • DropdownMenuContent (243-243)
  • DropdownMenuItem (245-245)
apps/web/src/lib/task-helper.ts (2)
packages/types/src/primitives/TaskBoard.ts (4)
  • TaskBoardStatusTemplate (5-13)
  • TaskBoard (22-32)
  • TaskBoardStatus (3-3)
  • TaskList (34-46)
packages/ui/src/components/ui/sonner.tsx (1)
  • toast (29-29)
🪛 GitHub Check: codecov/patch
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-summary.tsx

[warning] 137-137: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-summary.tsx#L137
Added line #L137 was not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx

[warning] 5-5: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx#L5
Added line #L5 was not covered by tests


[warning] 14-14: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx#L14
Added line #L14 was not covered by tests


[warning] 17-17: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx#L17
Added line #L17 was not covered by tests


[warning] 19-20: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/list-view.tsx#L19-L20
Added lines #L19 - L20 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx

[warning] 3-19: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L3-L19
Added lines #L3 - L19 were not covered by tests


[warning] 21-29: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L21-L29
Added lines #L21 - L29 were not covered by tests


[warning] 37-38: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L37-L38
Added lines #L37 - L38 were not covered by tests


[warning] 45-45: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L45
Added line #L45 was not covered by tests


[warning] 49-49: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L49
Added line #L49 was not covered by tests


[warning] 52-53: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L52-L53
Added lines #L52 - L53 were not covered by tests


[warning] 55-55: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L55
Added line #L55 was not covered by tests


[warning] 58-58: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L58
Added line #L58 was not covered by tests


[warning] 60-62: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L60-L62
Added lines #L60 - L62 were not covered by tests


[warning] 65-112: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L65-L112
Added lines #L65 - L112 were not covered by tests


[warning] 117-117: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L117
Added line #L117 was not covered by tests


[warning] 126-142: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L126-L142
Added lines #L126 - L142 were not covered by tests


[warning] 144-249: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L144-L249
Added lines #L144 - L249 were not covered by tests


[warning] 252-276: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L252-L276
Added lines #L252 - L276 were not covered by tests


[warning] 278-325: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-header.tsx#L278-L325
Added lines #L278 - L325 were not covered by tests

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx

[warning] 4-4: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L4
Added line #L4 was not covered by tests


[warning] 6-6: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L6
Added line #L6 was not covered by tests


[warning] 14-16: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L14-L16
Added lines #L14 - L16 were not covered by tests


[warning] 22-23: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L22-L23
Added lines #L22 - L23 were not covered by tests


[warning] 26-27: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L26-L27
Added lines #L26 - L27 were not covered by tests


[warning] 29-34: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L29-L34
Added lines #L29 - L34 were not covered by tests


[warning] 36-69: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L36-L69
Added lines #L36 - L69 were not covered by tests


[warning] 72-72: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L72
Added line #L72 was not covered by tests


[warning] 74-76: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L74-L76
Added lines #L74 - L76 were not covered by tests


[warning] 78-80: apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/_components/board-views.tsx#L78-L80
Added lines #L78 - L80 were not covered by tests

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Deploy-Preview
🔇 Additional comments (28)
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/page.tsx (1)

51-51: LGTM!

Adding the requireExpansion prop to show the feature summary in expanded state by default.

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/kanban.tsx (4)

17-25: Good sensor simplification.

Consolidating to a single PointerSensor with activation distance simplifies the drag-and-drop setup while maintaining both mouse and touch support.

Also applies to: 98-102


55-67: Excellent backward compatibility handling.

The column enhancement maintains the title property for backward compatibility while adopting the full TaskList objects with their new status and color properties.


225-248: Smart optimization to prevent unnecessary mutations.

Adding the check to only perform the move mutation when the target list differs from the original prevents redundant API calls and potential race conditions.


283-297: Well-structured status-based sorting.

The sorting logic clearly prioritizes lists by status (not_started → active → done → closed) and then by position within each status group, providing a logical board layout.

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task-list.tsx (2)

13-15: Clean interface extension

The Column interface properly extends TaskList, inheriting the necessary properties (color, status, position) as documented.


26-38: Well-structured color mapping

The colorClasses mapping provides consistent styling for all supported colors with appropriate opacity values for borders and backgrounds.

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/form.tsx (1)

188-404: Excellent template selection implementation

The template selection UI is well-designed with:

  • Proper loading states with skeletons
  • Clear blank board option
  • Accessible radio group implementation
  • Informative template previews with color-coded statuses
  • Good responsive design with @container queries
apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/task.tsx (7)

1-90: Well-structured component setup with appropriate imports.

The new imports and state management setup align well with the enhanced functionality. Good separation of concerns with dedicated state variables for different UI states.


143-164: Robust inline editing implementation.

Good validation with trim() to prevent empty names and proper handling of the optional description field.


179-207: Clean date handling implementation.

Proper use of ISO string format for date storage and correct null handling for date removal.


253-280: Well-designed priority indicator with good accessibility.

Nice touch using text-gray-900 for the yellow background to ensure proper contrast. The priority labels are clear and user-friendly.


342-387: Excellent inline editing UX with keyboard shortcuts.

The implementation includes thoughtful touches like autoFocus, Enter/Escape key handling, and proper state restoration on cancel.


435-552: Comprehensive date picker with excellent UX.

Great implementation with quick date options covering common use cases and a full calendar for custom dates. The popover positioning and controlled state management are well handled.


756-793: Safe delete implementation with proper confirmation.

Good UX with clear confirmation message showing the task name and loading feedback during the operation.

apps/web/src/app/[locale]/(dashboard)/[wsId]/tasks/boards/[boardId]/status-section.tsx (3)

1-82: Well-organized status configuration and drag-drop setup.

Clean separation of status metadata into dedicated objects. The useDroppable integration follows the library's patterns correctly.


95-125: Clear and informative status header design.

Good use of badges to display counts and the conditional "Tasks hidden" indicator provides clear feedback to users.


183-204: Proper enforcement of closed list limitation.

Good implementation of the business rule limiting closed status to one list. The disabled state and explanatory text provide clear feedback to users.

packages/types/src/primitives/TaskBoard.ts (2)

1-21: Well-designed type system for status workflows.

The template-based approach provides good flexibility for different board configurations. The allow_multiple field in TaskBoardStatusDefinition properly supports business rules like the single closed list limitation.


30-56: Good use of nullable pattern for end_date.

The change from end_date?: string to end_date?: string | null properly distinguishes between unset and explicitly cleared dates, which aligns with the date removal functionality in the UI.

apps/db/supabase/migrations/20250608140008_add_task_statuses.sql (2)

84-104:

✅ Verification successful

Verify the 'deleted' column exists in task_lists table.

The trigger references a deleted column for soft delete functionality, but this column is not defined in the current migration.

Run the following script to verify the column exists:


🏁 Script executed:

#!/bin/bash
# Description: Check if 'deleted' column exists in task_lists table definition

# Search for task_lists table creation or alteration adding deleted column
rg -B 5 -A 10 "CREATE TABLE.*task_lists|ALTER TABLE.*task_lists.*ADD.*deleted" --glob "*.sql"

# Also check for any soft delete implementations
rg "deleted.*BOOLEAN|soft.*delete" --glob "*.sql" -A 2 -B 2

Length of output: 2835


Deleted column exists in task_lists table

The deleted column is already defined in the initial migration, so the ensure_single_closed_list trigger can safely reference it.

• apps/db/supabase/migrations/20230202082703_remote_commit.sql: defines deleted boolean DEFAULT false on task_lists


1-13:

✅ Verification successful

Verify uuid-ossp extension is installed.

The migration uses uuid_generate_v4() which requires the uuid-ossp extension.

Run the following script to verify the extension exists:


🏁 Script executed:

#!/bin/bash
# Description: Check if uuid-ossp extension is created in other migrations

# Search for uuid-ossp extension creation
rg -A 2 "CREATE EXTENSION.*uuid-ossp" --glob "*.sql"

# Also check for the newer gen_random_uuid() function usage as alternative
rg "gen_random_uuid" --glob "*.sql"

Length of output: 11078


uuid-ossp extension already created

  • Verified that CREATE EXTENSION IF NOT EXISTS "uuid-ossp" is present in apps/db/supabase/migrations/20230202082703_remote_commit.sql, so uuid_generate_v4() will work without additional setup.

No changes required.

apps/web/src/lib/task-helper.ts (3)

168-169: Excellent implementation of status-based task archiving.

The logic to automatically archive tasks when moved to 'done' or 'closed' lists is a smart feature that maintains data consistency.


594-618: Good validation for closed status constraint.

The implementation correctly enforces that only one list per board can have the 'closed' status, preventing data inconsistency.


663-672: Good implementation of list grouping by status.

The reduce function efficiently groups task lists by their status, making it easy to display status-grouped boards.

packages/types/src/supabase.ts (3)

3504-3511: Well-designed task list enhancements!

The new fields (color, position, status) are properly typed and nullable, ensuring backward compatibility. The use of the enum type for status provides good type safety.

Also applies to: 3522-3523, 3534-3535


3816-3816: Template relationship properly implemented!

The template_id field and its foreign key relationship to task_board_status_templates are correctly configured. The nullable field ensures backward compatibility for existing boards.

Also applies to: 3826-3826, 3836-3836, 3861-3867


3216-3217:

❓ Verification inconclusive

Verify the impact of function signature reorderings.

Multiple function signatures have been reordered, which could be breaking changes for existing code. For example:

  • create_ai_chat: parameter order changed
  • generate_cross_app_token: parameters reordered
  • get_daily_income_expense: both parameters and return fields reordered

Please ensure that all consumers of these functions have been updated accordingly.

Run the following script to check for potential usage of these functions:

Also applies to: 3223-3226, 3237-3238, 3244-3249


🏁 Script executed:

#!/bin/bash
# Description: Search for usage of functions with reordered signatures

# Check for create_ai_chat usage
echo "=== Checking create_ai_chat usage ==="
rg -A 2 "create_ai_chat\s*\(" --type ts --type tsx --type js --type jsx

# Check for generate_cross_app_token usage
echo -e "\n=== Checking generate_cross_app_token usage ==="
rg -A 2 "generate_cross_app_token\s*\(" --type ts --type tsx --type js --type jsx

# Check for get_daily_income_expense usage
echo -e "\n=== Checking get_daily_income_expense usage ==="
rg -A 2 "get_daily_income_expense\s*\(" --type ts --type tsx --type js --type jsx

# Check for other affected functions
echo -e "\n=== Checking other affected functions ==="
rg -A 2 "(get_challenge_stats|get_monthly_income_expense|get_workspace_users|get_workspace_transactions_count)\s*\(" --type ts --type tsx --type js --type jsx

Length of output: 920


🏁 Script executed:

#!/bin/bash
# Re-run usage search without relying on built-in file type definitions
patterns=(
  "create_ai_chat"
  "generate_cross_app_token"
  "get_daily_income_expense"
  "get_challenge_stats"
  "get_monthly_income_expense"
  "get_workspace_users"
  "get_workspace_transactions_count"
)

for p in "${patterns[@]}"; do
  echo "=== Checking ${p} usage ==="
  rg -n "${p}\s*\(" --glob "*.ts" --glob "*.tsx" --glob "*.js" --glob "*.jsx"
done

Length of output: 1778


Verify external consumers for signature reordering

The following exported functions in packages/types/src/supabase.ts have had their parameters and/or return-value fields reordered, which is a breaking change for any callers relying on positional arguments or tuple-style destructuring:

  • create_ai_chat
  • generate_cross_app_token
  • get_daily_income_expense
  • get_challenge_stats
  • get_monthly_income_expense
  • get_workspace_users
  • get_workspace_transactions_count

No internal usage was found within this repo, so please manually confirm that all external clients or dependent packages have updated their calls (and any destructuring of return values) to match the new signatures. Consider adding a migration guide and bumping the major version to clearly communicate these breaking changes.

@vhpx vhpx merged commit 5b2f88c into main Jun 8, 2025
18 of 19 checks passed
@vhpx vhpx deleted the feat/add-task-statuses branch June 8, 2025 17:25
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.

1 participant