LinkDesk/backend/docs/custom-task-status-reorder-...

9.2 KiB

Custom Task Status Reorder Endpoint

Overview

This document describes the PATCH endpoint for reordering custom task statuses within a project. The endpoint allows coordinators and administrators to change the display order of custom task statuses.

Endpoint

PATCH /projects/{project_id}/task-statuses/reorder

Authentication

Requires JWT authentication with coordinator or admin role.

Request

Path Parameters

  • project_id (integer, required): The ID of the project

Request Body

{
  "status_ids": ["custom_abc123", "custom_def456", "custom_ghi789"]
}

Fields:

  • status_ids (array of strings, required): Ordered list of status IDs in the desired sequence
    • Must contain all existing custom status IDs for the project
    • Cannot contain duplicates
    • Cannot be empty

Response

Success Response (200 OK)

{
  "message": "Custom task statuses reordered successfully",
  "status": null,
  "all_statuses": {
    "statuses": [
      {
        "id": "custom_abc123",
        "name": "Review",
        "color": "#9333EA",
        "order": 0,
        "is_default": false
      },
      {
        "id": "custom_def456",
        "name": "Blocked",
        "color": "#DC2626",
        "order": 1,
        "is_default": true
      },
      {
        "id": "custom_ghi789",
        "name": "Ready for Delivery",
        "color": "#059669",
        "order": 2,
        "is_default": false
      }
    ],
    "system_statuses": [
      {
        "id": "not_started",
        "name": "Not Started",
        "color": "#6B7280",
        "is_system": true
      },
      {
        "id": "in_progress",
        "name": "In Progress",
        "color": "#3B82F6",
        "is_system": true
      },
      {
        "id": "submitted",
        "name": "Submitted",
        "color": "#F59E0B",
        "is_system": true
      },
      {
        "id": "approved",
        "name": "Approved",
        "color": "#10B981",
        "is_system": true
      },
      {
        "id": "retake",
        "name": "Retake",
        "color": "#EF4444",
        "is_system": true
      }
    ],
    "default_status_id": "custom_def456"
  }
}

Error Responses

400 Bad Request - Missing Status IDs

{
  "detail": "Missing status IDs in reorder request: custom_xyz999"
}

Occurs when the request doesn't include all existing custom status IDs.

400 Bad Request - Invalid Status IDs

{
  "detail": "Status IDs not found: invalid_id_12345"
}

Occurs when the request includes status IDs that don't exist in the project.

403 Forbidden

{
  "detail": "Insufficient permissions"
}

Occurs when the user doesn't have coordinator or admin role.

404 Not Found

{
  "detail": "Project not found"
}

Occurs when the specified project doesn't exist.

422 Unprocessable Entity - Duplicate IDs

{
  "detail": "1 validation error for CustomTaskStatusReorder\nstatus_ids\n  Value error, Status IDs list contains duplicates"
}

Occurs when the request contains duplicate status IDs.

422 Unprocessable Entity - Empty List

{
  "detail": "1 validation error for CustomTaskStatusReorder\nstatus_ids\n  Value error, Status IDs list cannot be empty"
}

Occurs when the request contains an empty status_ids array.

Implementation Details

Validation

  1. Project Existence: Verifies the project exists
  2. Permission Check: Ensures user has coordinator or admin role
  3. Complete List: Validates that all existing custom status IDs are included
  4. No Missing IDs: Ensures no status IDs are omitted
  5. No Invalid IDs: Ensures all provided IDs exist in the project
  6. No Duplicates: Validates the list contains no duplicate IDs (handled by Pydantic schema)

Order Update Process

  1. Parse and validate the reorder request
  2. Retrieve existing custom statuses from the project
  3. Create a mapping of status_id to status data
  4. Reorder statuses according to the provided list
  5. Update the order field for each status (0-indexed)
  6. Save the reordered list to the database
  7. Use flag_modified() to ensure JSON column changes are persisted

Database Changes

  • Updates the custom_task_statuses JSON column in the projects table
  • Each status object's order field is updated to match its position in the new list
  • Uses SQLAlchemy's flag_modified() to ensure JSON column changes are detected

Usage Examples

Python (requests)

import requests

# Login and get token
response = requests.post(
    "http://localhost:8000/auth/login",
    json={"email": "admin@vfx.com", "password": "admin123"}
)
token = response.json()["access_token"]

# Reorder statuses
headers = {"Authorization": f"Bearer {token}"}
data = {
    "status_ids": [
        "custom_abc123",
        "custom_def456",
        "custom_ghi789"
    ]
}

response = requests.patch(
    "http://localhost:8000/projects/1/task-statuses/reorder",
    headers=headers,
    json=data
)

if response.status_code == 200:
    result = response.json()
    print(f"✅ {result['message']}")
    print(f"Reordered {len(result['all_statuses']['statuses'])} statuses")
else:
    print(f"❌ Error: {response.json()['detail']}")

JavaScript (fetch)

// Assuming you have a token from login
const token = "your_jwt_token_here";

const reorderStatuses = async (projectId, statusIds) => {
  const response = await fetch(
    `http://localhost:8000/projects/${projectId}/task-statuses/reorder`,
    {
      method: 'PATCH',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        status_ids: statusIds
      })
    }
  );

  if (response.ok) {
    const result = await response.json();
    console.log('✅', result.message);
    return result.all_statuses;
  } else {
    const error = await response.json();
    console.error('❌ Error:', error.detail);
    throw new Error(error.detail);
  }
};

// Usage
const statusIds = [
  'custom_abc123',
  'custom_def456',
  'custom_ghi789'
];

reorderStatuses(1, statusIds)
  .then(allStatuses => {
    console.log('New order:', allStatuses.statuses);
  })
  .catch(error => {
    console.error('Failed to reorder:', error);
  });

Frontend Integration

Drag-and-Drop Implementation

The frontend should implement drag-and-drop functionality using a library like vue-draggable-next:

  1. Display statuses in their current order
  2. Allow users to drag statuses to reorder them
  3. On drop, collect the new order of status IDs
  4. Call the reorder endpoint with the new order
  5. Update the UI optimistically or wait for the response
  6. Handle errors by reverting to the previous order

Example Vue Component

<template>
  <draggable
    v-model="statuses"
    @end="handleReorder"
    item-key="id"
  >
    <template #item="{ element }">
      <div class="status-item">
        <span class="drag-handle">⋮⋮</span>
        <span :style="{ color: element.color }">
          {{ element.name }}
        </span>
      </div>
    </template>
  </draggable>
</template>

<script setup>
import { ref } from 'vue';
import draggable from 'vuedraggable';
import { reorderTaskStatuses } from '@/services/customTaskStatus';

const props = defineProps({
  projectId: Number,
  initialStatuses: Array
});

const statuses = ref([...props.initialStatuses]);

const handleReorder = async () => {
  const statusIds = statuses.value.map(s => s.id);
  
  try {
    const result = await reorderTaskStatuses(props.projectId, statusIds);
    // Update with server response
    statuses.value = result.all_statuses.statuses;
  } catch (error) {
    // Revert to original order on error
    statuses.value = [...props.initialStatuses];
    console.error('Failed to reorder:', error);
  }
};
</script>

Testing

A comprehensive test script is available at backend/test_reorder_custom_task_status.py that tests:

  1. Successful reordering (reversing order)
  2. Order field updates correctly
  3. Rejection of incomplete status lists
  4. Rejection of invalid status IDs
  5. Rejection of duplicate status IDs

Run the test with:

cd backend
python test_reorder_custom_task_status.py

Requirements Validation

This endpoint satisfies the following requirements from the custom task status specification:

  • Requirement 4.1: Displays statuses in their defined order
  • Requirement 4.2: Updates the order when user reorders statuses
  • Requirement 4.3: Updates display order in all dropdowns and filters
  • Requirement 4.4: Validates all status IDs are present
  • GET /projects/{project_id}/task-statuses - Get all task statuses
  • POST /projects/{project_id}/task-statuses - Create a custom status
  • PUT /projects/{project_id}/task-statuses/{status_id} - Update a custom status
  • DELETE /projects/{project_id}/task-statuses/{status_id} - Delete a custom status

Notes

  • System statuses (not_started, in_progress, submitted, approved, retake) cannot be reordered
  • Only custom statuses can be reordered
  • The order field is 0-indexed
  • Reordering does not affect the default status designation
  • The endpoint uses flag_modified() to ensure JSON column changes are persisted to the database