# Shot Table AJAX Task Status Update Implementation

## Overview

This document describes the implementation of AJAX-based task status editing in the shot table view. Previously, task status columns displayed read-only badges. Now they use editable dropdowns that update task status via API calls without page refresh.

## Changes Made

### 1. Created Shot-Specific EditableTaskStatus Component

**File**: `frontend/src/components/shot/EditableTaskStatus.vue`

Created a new component specifically for editing shot task statuses, similar to the existing asset version but adapted for shots:

**Features**:
- Dropdown select with status options
- Loading indicator during API calls
- Automatic task creation if task doesn't exist
- Status update via AJAX
- Error handling with status revert
- Visual feedback during updates

**Props**:
- `shotId: number` - The shot ID
- `taskType: string` - The task type (layout, animation, etc.)
- `status: TaskStatus` - Current task status
- `taskId?: number | null` - Existing task ID (if task exists)

**Events**:
- `status-updated` - Emitted after successful status update

**API Calls**:
1. `taskService.createShotTask()` - Creates task if it doesn't exist
2. `taskService.updateTaskStatus()` - Updates the task status

### 2. Added createShotTask Method to Task Service

**File**: `frontend/src/services/task.ts`

Added new method to create shot tasks:

```typescript
async createShotTask(shotId: number, taskType: string): Promise<TaskStatusInfo> {
  const response = await apiClient.post(`/shots/${shotId}/tasks?task_type=${taskType}`)
  return response.data
}
```

This mirrors the existing `createAssetTask` method but for shots.

### 3. Updated Shot Interface

**File**: `frontend/src/services/shot.ts`

Added `task_ids` field to Shot interface for easier access to task IDs:

```typescript
export interface Shot {
  // ... existing fields ...
  task_ids?: Record<string, number>
}
```

This allows the editable component to know if a task already exists and its ID.

### 4. Updated Shot Table Columns

**File**: `frontend/src/components/shot/columns.ts`

**Changes**:
1. Imported `EditableTaskStatus` component
2. Added `onTaskStatusUpdated` callback to `ShotColumnMeta` interface
3. Updated task status column cells to use `EditableTaskStatus` instead of `TaskStatusBadge`

**Column Cell Implementation**:
```typescript
cell: ({ row }) => {
  const shot = row.original
  const status = shot.task_status?.[taskType] || TaskStatus.NOT_STARTED
  const taskId = shot.task_ids?.[taskType]
  
  return h(EditableTaskStatus, {
    shotId: shot.id,
    taskType,
    status,
    taskId,
    onStatusUpdated: (shotId: number, taskType: string, newStatus: TaskStatus) => {
      meta.onTaskStatusUpdated(shotId, taskType, newStatus)
    },
  })
}
```

### 5. Updated ShotBrowser Component

**File**: `frontend/src/components/shot/ShotBrowser.vue`

**Changes**:
1. Imported `TaskStatus` enum
2. Added `handleTaskStatusUpdated` method
3. Passed callback to column meta

**Handler Implementation**:
```typescript
const handleTaskStatusUpdated = (shotId: number, taskType: string, newStatus: TaskStatus) => {
  // Update local state instead of reloading all shots (optimistic update)
  const shot = shots.value.find(s => s.id === shotId)
  if (shot) {
    if (!shot.task_status) {
      shot.task_status = {}
    }
    shot.task_status[taskType] = newStatus
  }
  
  // Show success toast
  toast({
    title: 'Task status updated',
    description: `${taskType} status updated successfully`,
  })
}
```

**Key Improvement**: Uses optimistic local state update instead of reloading all shots from the server, matching the asset table behavior for better performance.

**Column Meta Update**:
```typescript
const shotColumns = computed(() => {
  const meta: ShotColumnMeta = {
    episodes: episodes.value,
    onEdit: editShot,
    onDelete: deleteShot,
    onViewTasks: selectShot,
    onTaskStatusUpdated: handleTaskStatusUpdated, // Added
  }
  return createShotColumns(allTaskTypes.value, meta)
})
```

## User Experience Flow

### Editing Task Status

1. User clicks on a task status cell in the shot table
2. Dropdown opens showing all available statuses
3. User selects a new status
4. Component shows loading indicator
5. If task doesn't exist:
   - API call creates the task
   - Task ID is returned
6. API call updates the task status
7. Success:
   - Shot list refreshes with new status
   - Toast notification appears
   - Loading indicator disappears
8. Error:
   - Status reverts to original
   - Error is logged to console
   - Parent component refreshes data

### Visual Feedback

- **Loading**: Spinner overlay on the dropdown
- **Success**: Toast notification + table refresh
- **Error**: Silent revert (status returns to original)

## Backend Implementation

### Added Endpoint: Create Shot Task

**File**: `backend/routers/shots.py`

Added new endpoint after `get_shot`:

```python
@router.post("/{shot_id}/tasks", response_model=TaskStatusInfo, status_code=status.HTTP_201_CREATED)
async def create_shot_task(
    shot_id: int,
    task_type: str,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_coordinator_or_admin)
):
    """Create a new task for a shot"""
    # Validates shot exists
    # Checks episode access permissions
    # Returns existing task if already exists (idempotent)
    # Creates new task with default values
    # Returns TaskStatusInfo with task_id
```

**Key Features**:
- Idempotent: Returns existing task if already created
- Permission check: Requires coordinator or admin role
- Access validation: Checks episode access via shot
- Auto-naming: Creates task name as "{shot_name} - {task_type}"

## API Endpoints Used

### Create Shot Task
```
POST /shots/{shot_id}/tasks?task_type={task_type}
```

**Response** (201 Created or 200 OK if exists):
```json
{
  "task_type": "animation",
  "status": "not_started",
  "task_id": 123,
  "assigned_user_id": null
}
```

### Update Task Status
```
PUT /tasks/{task_id}/status
```

**Request Body**:
```json
{
  "status": "in_progress"
}
```

**Response**: Updated task object

### Get Shots (with task status)
```
GET /shots/?episode_id={episode_id}
```

**Response**: Array of shots with `task_status` and `task_ids` populated

## Benefits

1. **No Page Refresh**: Status updates happen instantly via AJAX
2. **Automatic Task Creation**: Tasks are created on-demand when status is first changed
3. **Visual Feedback**: Loading indicators and toast notifications
4. **Error Handling**: Graceful error handling with status revert
5. **Consistent UX**: Matches the asset table behavior
6. **Performance**: Only affected shot data is refreshed

## Technical Details

### Task Creation Flow

When a user changes status for a task that doesn't exist:

1. Component checks if `taskId` prop is provided
2. If not, calls `createShotTask(shotId, taskType)`
3. Backend creates task with default values
4. Returns task ID
5. Component then calls `updateTaskStatus(taskId, newStatus)`
6. Status is updated
7. Parent refreshes to show new data

### Status Update Flow

When a user changes status for an existing task:

1. Component has `taskId` from props
2. Directly calls `updateTaskStatus(taskId, newStatus)`
3. Status is updated
4. Parent refreshes to show new data

### Data Refresh Strategy

After status update:
- **Optimistic Update**: Local state is updated immediately
- Shot's `task_status` object is modified directly
- No server reload required
- Matches asset table behavior for consistent UX
- Much faster than reloading all shots

## Comparison with Asset Table

The shot table implementation mirrors the asset table:

| Feature | Asset Table | Shot Table |
|---------|-------------|------------|
| Component | `EditableTaskStatus.vue` (asset) | `EditableTaskStatus.vue` (shot) |
| Create Method | `createAssetTask()` | `createShotTask()` |
| Update Method | `updateTaskStatus()` | `updateTaskStatus()` (same) |
| Column Definition | `columns.ts` (asset) | `columns.ts` (shot) |
| Parent Handler | `AssetBrowser` | `ShotBrowser` |

## Future Enhancements

Potential improvements:

1. **Optimistic Updates**: Update UI immediately, revert on error
2. **Batch Updates**: Allow updating multiple tasks at once
3. **Undo/Redo**: Add ability to undo status changes
4. **Keyboard Shortcuts**: Quick status changes via keyboard
5. **Status History**: Track who changed status and when
6. **Validation**: Prevent invalid status transitions
7. **Permissions**: Check user permissions before allowing edits

## Testing

To test the implementation:

1. Navigate to a project's Shots tab
2. Switch to table view
3. Find a shot with tasks
4. Click on a task status cell
5. Select a different status
6. Verify:
   - Loading indicator appears
   - Status updates in table
   - Toast notification shows
   - No page refresh occurs
7. Test with a shot that has no tasks:
   - Change status
   - Verify task is created
   - Verify status is set correctly

## Related Files

- `frontend/src/components/shot/EditableTaskStatus.vue` - Editable status component
- `frontend/src/components/shot/columns.ts` - Column definitions
- `frontend/src/components/shot/ShotBrowser.vue` - Parent component
- `frontend/src/services/task.ts` - Task service with API methods
- `frontend/src/services/shot.ts` - Shot service and types
- `frontend/src/components/asset/EditableTaskStatus.vue` - Asset version (reference)

## Conclusion

The shot table now supports AJAX-based task status editing, providing a seamless user experience without page refreshes. The implementation follows the same pattern as the asset table, ensuring consistency across the application.
