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 |
|---|---|---|
|
Return only tasks from a specific contract |
|
|
Return tasks created after this date-time |
|
|
Return tasks created before this date-time (requires |
|
|
Maximum number of tasks per page (default: 10) |
|
|
Pagination cursor from previous response |
|
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:
-
Contract filter → API call (reduces data transfer)
-
Status filter → Client-side (instant response)
-
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 taskabc12345-6789-… -
User types partial ID → sees matches as they type
-
Case-insensitive → less friction
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.
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
cursorvalue from each response -
Pass it in the next request to get the next page
-
When
cursoris 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
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:
-
Load data – Fetch contracts (for filter dropdown) and tasks on mount
-
Filter and search – Apply API-side and client-side filters
-
Sort – Order results by user preference
-
Display – Show summary info with visual cues
-
Navigate – Click through to full details
-
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.