LinkDesk/frontend/docs/context-menu-selection-pres...

3.2 KiB

Context Menu Selection Preservation Fix

Issue

When right-clicking on an unselected task, all previously selected tasks were being deselected, leaving only the right-clicked task selected.

Expected Behavior

According to Requirement 3.2: "WHEN a user right-clicks on an unselected task row THEN the system SHALL select that task and display the context menu"

The requirement means:

  • If the right-clicked task is already selected → keep all selections, show menu
  • If the right-clicked task is NOT selected → ADD it to existing selections, show menu

Root Cause

The implementation was replacing the entire selection object instead of adding to it:

// WRONG - Replaces all selections
if (!rowSelection.value[rowIndex]) {
  rowSelection.value = { [rowIndex]: true }
}

This cleared all existing selections and only selected the right-clicked row.

Solution

Use the spread operator to preserve existing selections while adding the new row:

// CORRECT - Preserves existing selections
if (!rowSelection.value[rowIndex]) {
  rowSelection.value = { ...rowSelection.value, [rowIndex]: true }
}

Implementation

Before

const handleContextMenu = (event: MouseEvent, rowIndex: number) => {
  event.preventDefault()
  
  if (filteredTasks.value.length === 0) {
    return
  }
  
  // This replaces all selections!
  if (!rowSelection.value[rowIndex]) {
    rowSelection.value = { [rowIndex]: true }
  }
  
  contextMenuPosition.value = { x: event.clientX, y: event.clientY }
  showContextMenu.value = true
}

After

const handleContextMenu = (event: MouseEvent, rowIndex: number) => {
  event.preventDefault()
  
  if (filteredTasks.value.length === 0) {
    return
  }
  
  // Preserve existing selections and add the right-clicked row
  if (!rowSelection.value[rowIndex]) {
    rowSelection.value = { ...rowSelection.value, [rowIndex]: true }
  }
  
  contextMenuPosition.value = { x: event.clientX, y: event.clientY }
  showContextMenu.value = true
}

Testing

Test Scenario 1: Right-click on unselected task with existing selections

  1. Select tasks 1, 2, and 3 using checkboxes
  2. Right-click on task 4 (unselected)
  3. Expected: Tasks 1, 2, 3, and 4 are all selected
  4. Result: All 4 tasks remain selected

Test Scenario 2: Right-click on already selected task

  1. Select tasks 1, 2, and 3 using checkboxes
  2. Right-click on task 2 (already selected)
  3. Expected: Tasks 1, 2, and 3 remain selected
  4. Result: All 3 tasks remain selected

Test Scenario 3: Right-click with no prior selections

  1. No tasks selected
  2. Right-click on task 1
  3. Expected: Task 1 becomes selected
  4. Result: Task 1 is selected

Files Modified

  • frontend/src/components/task/TaskBrowser.vue - Fixed handleContextMenu to preserve selections
  • Requirement 3.2: Right-click on unselected task should select it before showing menu
  • Requirement 1.2: User can toggle selection state for specific tasks
  • Requirement 1.3: Header checkbox toggles selection for all visible tasks

Benefits

  • Preserves user's existing selections
  • Allows building up selections via right-click
  • Matches expected UX behavior
  • Complies with Requirement 3.2