Manage and monitor tasks

This guide teaches you how to view and manage your existing tasking requests. We’ll continue using the ICEYE Tasking Demo as a concrete reference.

Prerequisites

This guide builds on Build a Tasking Application. If you haven’t read it yet, start there to understand the fundamentals of task creation and monitoring.

Why task management matters

Creating tasks is just the beginning. In real-world applications, users need to:

  • Return to check progress – Tasks take time. Users close the browser and come back later.

  • Find specific tasks – Locate a particular task by ID, reference name, or other criteria.

  • Filter by status – Focus on active tasks, completed tasks, or those requiring attention.

  • Review history – Understand task volume and patterns over time.

The demo’s "View All Tasks" feature addresses all of these needs.

Part 1: Listing tasks

Understanding the list endpoint

The Tasking API provides a dedicated endpoint to retrieve all your tasks:

GET /tasking/v2/tasks
Authorization: Bearer {token}

What you get back:

{
  "cursor": "next-page-cursor",
  "data": [
    {
      "id": "task-uuid-1",
      "status": "DONE",
      "imagingMode": "SCAN",
      "contractID": "contract-uuid",
      "reference": "Helsinki Port Monitoring",
      "createdAt": "2025-01-15T10:30:00Z",
      "updatedAt": "2025-01-16T14:20:00Z",
      "pointOfInterest": { "lat": 60.1699, "lon": 24.9384 },
      "acquisitionWindow": {
        "start": "2025-01-16T00:00:00Z",
        "end": "2025-01-17T00:00:00Z"
      },
      "sla": "SLA_24H",
      "productTypes": ["GRD", "SLC"]
    }
  ]
}

Notice the response includes everything you need to display a useful task list: status, reference name, imaging mode, timestamps, and more.

Loading tasks on component mount

The demo loads tasks when the user navigates to the task list view:

// frontend/src/components/TaskList.jsx
useEffect(() => {
  loadContracts()  // For the filter dropdown
  loadTasks()      // The main task list
}, [])
Load both contracts and tasks on mount. You’ll need contracts for the filter dropdown, and loading them together means the UI is ready faster.

What information to display

You can decide which fields are most relevant to display based on your users' needs. The API returns many fields per task – your UI should surface the ones that help users quickly identify and understand their tasks.

For the demo, we chose to display:

Column Why we included it

Task ID

Unique identifier for API calls and support

Created date

Helps users find recent tasks

Reference

User’s own name for the task

Imaging mode

SCAN, SPOT, etc.

Acquisition window

When imaging is scheduled

Products

What product types are included

SLA

Delivery timeframe expectation

Status

Current state – often the most important field

Your application might prioritize different fields. For example, an operations dashboard might emphasize acquisition windows and status, while a billing application might focus on contract IDs and product counts.

For tasks with status ACTIVE, FULFILLED, or DONE, you can call the Get Task Scene endpoint to retrieve the planned or actual imaging time. This is more precise than the acquisition window, which only defines when imaging could happen.

Part 2: Filtering tasks

Users with many tasks need ways to narrow down the list. The API provides several filtering options.

Available API filters

The List Tasks endpoint supports these query parameters for server-side filtering:

Parameter Description Example

contractID

Return only tasks from a specific contract

?contractID=abc123-…​

createdAfter

Return tasks created after this date-time

?createdAfter=2025-01-01T00:00:00Z

createdBefore

Return tasks created before this date-time (requires createdAfter)

?createdAfter=2025-01-01T00:00:00Z&createdBefore=2025-01-31T23:59:59Z

limit

Maximum number of tasks per page (default: 10)

?limit=50

cursor

Pagination cursor from previous response

?cursor=xyz…​

Server-side filtering is more efficient because only matching tasks are transferred over the network. If you have 500 tasks across 10 contracts and the user only wants one contract’s tasks, API-side filtering transfers 50 tasks instead of 500.

How the demo uses API filters

The demo implements contract filtering as an API-side filter:

const handleContractFilterChange = (e) => {
  const newContractId = e.target.value
  setContractFilter(newContractId)

  // Re-fetch from API with new filter – don't just filter locally
  loadTasks(newContractId)
}

Client-side filtering

For filters not supported by the API, or when you want instant feedback without an API call, filter the already-loaded data in the browser.

The demo uses client-side filtering for status:

const filteredTasks = tasks.filter(task => {
  if (statusFilter && task.status !== statusFilter) return false
  return true
})

Combining both approaches

A good strategy is to use API filters for high-impact narrowing (like contract), and client-side filters for quick refinements (like status or search):

const filteredTasks = tasks.filter(task => {
  // Status filter (client-side)
  if (statusFilter && task.status !== statusFilter) return false
  // Search filter (client-side)
  if (searchId && !task.id.toLowerCase().includes(searchId.toLowerCase())) return false
  return true
})

The demo applies this pattern:

  1. Contract filter → API call (reduces data transfer)

  2. Status filter → Client-side (instant response)

  3. Search → Client-side (instant response)

Part 3: Searching tasks

Sometimes users know exactly which task they want and have a task ID they want to find.

Partial matching is user-friendly

Users might not have the full UUID, so the demo uses partial matching:

const filteredTasks = tasks.filter(task => {
  if (searchId && !task.id.toLowerCase().includes(searchId.toLowerCase())) {
    return false
  }
  return true
})

Why includes() instead of exact match?

  • User pastes abc12345 → finds task abc12345-6789-…​

  • User types partial ID → sees matches as they type

  • Case-insensitive → less friction

Providing clear feedback

Show users what’s happening:

{searchId && (
  <span>Found {filteredTasks.length} of {tasks.length} tasks</span>
)}

This confirms their search is working and shows how many results matched.

Part 4: Sorting tasks

Users think about their tasks in different ways: "most recent first," "show me active tasks," "alphabetically by reference."

Making columns sortable

The demo allows sorting by clicking column headers:

const handleSort = (field) => {
  if (field === sortField) {
    // Same column – toggle direction
    setSortOrder(sortOrder === 'DESC' ? 'ASC' : 'DESC')
  } else {
    // Different column – default to descending (newest/highest first)
    setSortField(field)
    setSortOrder('DESC')
  }
}

Why descending by default? For most columns (created date, status), users want to see the most recent or most important items first.

Visual feedback for sort state

Show users which column is sorted and in which direction:

<th onClick={() => handleSort('createdAt')}>
  Created {sortField === 'createdAt' && (sortOrder === 'DESC' ? '↓' : '↑')}
</th>

The arrow tells users: "This column is sorted, and clicking again will reverse it."

Part 5: Pagination

The List Tasks API returns results in pages (10 tasks by default). To retrieve more tasks, you need to handle pagination.

For a complete guide on how cursor-based pagination works across all ICEYE APIs, see Handle Pagination.

The demo implements a "Load More" button that uses the cursor from each response to fetch the next page. Key points:

  • Store the cursor value from each response

  • Pass it in the next request to get the next page

  • When cursor is absent or null, you’ve reached the end

  • Reset the cursor when filters change (cursors are tied to query parameters)

Part 6: Navigating to task details

The task list is a launching point. When users click a row, they expect to see full details.

Reusing the monitoring component

The demo reuses the same TaskMonitoring component used after task creation:

// In TaskList
<tr onClick={() => onTaskSelected(task)}>
  {/* ... */}
</tr>

// In App.jsx
const handleTaskSelected = (task) => {
  setSelectedTask(task)
  setView('monitor')
}

Why reuse?

  • Consistent experience – same UI whether viewing a new or existing task

  • Less code to maintain

  • Users learn one interface, not two

The task object as navigation state

Notice we pass the entire task object, not just the ID:

onTaskSelected(task)  // Pass the whole task

This means the monitoring view can display basic info immediately, then fetch fresh details. The user sees something right away instead of a loading spinner.

Part 7: Visual design patterns

This section shares patterns the demo uses for visual feedback. Adapt these to your application’s design system.

Status badges with color coding

Status is often the most important field. Color-coding helps users scan the list quickly. Here’s how the demo maps statuses to colors:

Status Color Meaning

RECEIVED

Blue

Task is queued

ACTIVE

Yellow/Orange

Satellite is scheduled

FULFILLED

Light green

SLA products ready

DONE

Green

All products ready

CANCELED

Gray

User canceled

FAILED

Red

Something went wrong

REJECTED

Red

ICEYE couldn’t fulfill

const getStatusClass = (status) => {
  const classes = {
    RECEIVED: 'status-received',
    ACTIVE: 'status-active',
    FULFILLED: 'status-fulfilled',
    DONE: 'status-done',
    CANCELED: 'status-canceled',
    FAILED: 'status-failed',
    REJECTED: 'status-rejected'
  }
  return classes[status] || 'status-default'
}

Copy-to-clipboard for IDs

Users frequently need to copy task IDs for API calls, support requests, or sharing with colleagues:

const handleCopyId = (e, id) => {
  e.stopPropagation()  // Don't trigger row click
  navigator.clipboard.writeText(id)
}
Use e.stopPropagation() so clicking the copy button doesn’t also navigate to the task details.

Putting it all together

Here’s the mental model for a task list component:

  1. Load data – Fetch contracts (for filter dropdown) and tasks on mount

  2. Filter and search – Apply API-side and client-side filters

  3. Sort – Order results by user preference

  4. Display – Show summary info with visual cues

  5. Navigate – Click through to full details

  6. Paginate – Load more results as needed

Each piece builds on the patterns established in the task creation guide: API calls, state management, and user feedback.

Try it yourself

Find the demo code on GitHub.

The key file for this guide is frontend/src/components/TaskList.jsx.