Skip to content

feat: issue 13 & issue 14#20

Open
keshxvdayal wants to merge 2 commits intomainfrom
feature/issue-13-14
Open

feat: issue 13 & issue 14#20
keshxvdayal wants to merge 2 commits intomainfrom
feature/issue-13-14

Conversation

@keshxvdayal
Copy link
Collaborator

@keshxvdayal keshxvdayal commented Jan 26, 2026

Issue #13 (SOLVED)

  • Solution -
    Used useCallback to memoize sorting function
    Proper React hooks dependencies
    Non-mutating sort (creates new array)
    Handles edge cases (null values, missing fields)
    Works seamlessly with existing search functionality

issue #14 (SOLVED)

Implementation Screenshot:

Screenshot 2026-01-27 at 1 19 06 AM Screenshot 2026-01-27 at 1 19 43 AM

Summary by Sourcery

Add sortable task table columns and improve task log loading for the dashboard.

New Features:

  • Enable client-side sorting of tasks by ID, name, status, TES instance, and creation time with visual sort indicators in the Tasks page.

Enhancements:

  • Integrate search and sorting so that task lists are first filtered then consistently sorted based on the selected column and direction.
  • Extend log loading in the Logs page to use the unified tasks collection, handle both legacy and new task ID fields, and include richer fallback metadata when logs are unavailable.
  • Increase the number of recent tasks whose logs are fetched from 10 to 20 for broader visibility into recent activity.

Copilot AI review requested due to automatic review settings January 26, 2026 19:50
@sourcery-ai
Copy link

sourcery-ai bot commented Jan 26, 2026

Reviewer's Guide

Implements sortable columns for the Tasks table with memoized, non-mutating sorting integrated with existing search, and updates Logs to consume the new dashboard task shape and provide richer, more resilient task log metadata and fallbacks.

Sequence diagram for the updated task table sorting and search

sequenceDiagram
  actor User
  participant TasksPage

  User->>TasksPage: Type in searchTerm
  activate TasksPage
  TasksPage->>TasksPage: setSearchTerm(newTerm)
  deactivate TasksPage

  loop Polling interval
    TasksPage->>TasksPage: usePolling(taskService.listTasks)
    TasksPage-->>TasksPage: tasksData updated
  end

  Note over TasksPage: useEffect runs when tasksData, searchTerm, sortColumn, sortDirection change

  TasksPage->>TasksPage: filter healthyTasks
  alt searchTerm present
    TasksPage->>TasksPage: tasksToDisplay = healthyTasks.filter(matches searchTerm)
  else no searchTerm
    TasksPage->>TasksPage: tasksToDisplay = healthyTasks
  end

  TasksPage->>TasksPage: sortTasks(tasksToDisplay)
  TasksPage-->>TasksPage: sortedTasks
  TasksPage->>TasksPage: setFilteredTasks(sortedTasks)

  User->>TasksPage: Click column header
  activate TasksPage
  TasksPage->>TasksPage: handleSort(column)
  alt column equals sortColumn
    TasksPage->>TasksPage: toggle sortDirection
  else new column
    TasksPage->>TasksPage: setSortColumn(column)
    TasksPage->>TasksPage: setSortDirection(asc)
  end
  deactivate TasksPage

  Note over TasksPage: State change triggers useEffect to reapply search and memoized sortTasks
Loading

Sequence diagram for loading logs from updated dashboard tasks

sequenceDiagram
  actor User
  participant LogsPage
  participant TaskService
  participant LogService

  User->>LogsPage: Open logs page
  activate LogsPage
  LogsPage->>TaskService: getDashboardData()
  TaskService-->>LogsPage: dashboardData (with tasks[])
  LogsPage->>LogsPage: console.log(Tasks found)

  alt dashboardData.tasks is array
    LogsPage->>LogsPage: for task in tasks.slice(-20)
    loop For each task
      LogsPage->>LogsPage: taskId = task.task_id or task.id
      LogsPage->>LogService: getTaskLogs(taskId, task.tes_url)
      LogService-->>LogsPage: logResponse
      alt logResponse.success is true
        LogsPage->>LogsPage: content = logResponse.log or success default
      else logResponse.log exists
        LogsPage->>LogsPage: content = logResponse.log
      else
        LogsPage->>LogsPage: content = fallback with task name, status or state, tes_name, submitted_at or creation_time
      end
      LogsPage->>LogsPage: build TaskLogEntry with id, title, content, timestamp, metadata
    end
  else tasks not array
    LogsPage->>LogsPage: no task logs loaded
  end

  LogsPage-->>User: Render logs list with enriched metadata
  deactivate LogsPage
Loading

Updated class diagram for dashboard tasks and task logs

classDiagram
  class TaskService {
    +getDashboardData()
    +listTasks()
  }

  class LogService {
    +getTaskLogs(taskId, tesUrl)
  }

  class DashboardData {
    +tasks: DashboardTask[]
  }

  class DashboardTask {
    +id: string
    +task_id: string
    +name: string
    +task_name: string
    +status: string
    +state: string
    +tes_name: string
    +tes_url: string
    +submitted_at: string
    +creation_time: string
    +type: string
  }

  class TaskLogEntry {
    +id: string
    +type: string
    +title: string
    +content: string
    +timestamp: string
    +metadata_status: string
    +metadata_tesInstance: string
  }

  TaskService --> DashboardData
  DashboardData --> DashboardTask
  LogsPage ..> TaskService
  LogsPage ..> LogService
  LogsPage ..> TaskLogEntry

  class LogsPage {
    +loadDashboardTasks()
    +buildTaskLogEntry(task, logResponse)
  }

  class TasksPage {
    +searchTerm: string
    +filteredTasks: DashboardTask[]
    +sortColumn: string
    +sortDirection: string
    +handleSort(column)
    +getSortIndicator(column)
    +sortTasks(tasks)
  }

  TasksPage ..> TaskService
  TasksPage ..> DashboardTask
Loading

File-Level Changes

Change Details Files
Add client-side sortable columns to the Tasks table and integrate sorting with existing search/filtering.
  • Extend table header styling to support clickable, hoverable sortable headers and a visual sort indicator component with active/inactive states.
  • Introduce sort column and direction state plus a header click handler that toggles or switches sort order per column.
  • Implement a memoized, non-mutating sortTasks helper that handles multiple task fields (id, name, state, TES instance, creation time) with null/missing value safety and date parsing.
  • Refactor the task filtering effect to first apply the existing search filter, then apply the new sortTasks function, keeping filteredTasks as the final derived list.
  • Wire each relevant table column header (Task ID, Name, Status, TES Instance, Created) to the sort handler and indicator to reflect current sort state.
frontend/src/pages/Tasks.js
Update Logs page to use the new dashboard task structure and enrich task log entries with flexible identifiers and metadata fallbacks.
  • Switch from submitted_tasks to tasks in dashboard data, adjusting log prefetch loop to use up to the last 20 tasks.
  • Handle both task.task_id and task.id when loading logs and constructing log entry IDs and titles, improving compatibility across task shapes.
  • Improve log content fallbacks when the log endpoint returns no content, including additional task details such as name, status/state, TES instance, submitted/creation times, and type.
  • Enhance error handling when fetching logs by emitting richer error log entries with the same improved metadata and fallback fields.
  • Adjust console logging to reflect the new tasks array and more descriptive log-loading messages.
frontend/src/pages/Logs.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In handleSort, consider using functional state updates (e.g., setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc')) to avoid potential issues with stale sortDirection when multiple state updates are batched.
  • The useEffect that updates filteredTasks depends on both sortTasks and sortColumn/sortDirection, even though sortTasks already depends on those; you can simplify the dependency array (or inline the sort logic) to avoid redundant dependencies.
  • In the logs error-handling branch, the pushed log object contains tesInstance both inside metadata and as a top-level field; if the extra top-level tesInstance isn't needed, removing it will keep the log shape consistent.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `handleSort`, consider using functional state updates (e.g., `setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc')`) to avoid potential issues with stale `sortDirection` when multiple state updates are batched.
- The `useEffect` that updates `filteredTasks` depends on both `sortTasks` and `sortColumn`/`sortDirection`, even though `sortTasks` already depends on those; you can simplify the dependency array (or inline the sort logic) to avoid redundant dependencies.
- In the logs error-handling branch, the pushed log object contains `tesInstance` both inside `metadata` and as a top-level field; if the extra top-level `tesInstance` isn't needed, removing it will keep the log shape consistent.

## Individual Comments

### Comment 1
<location> `frontend/src/pages/Logs.js:313` </location>
<code_context>
             if (logResponse && logResponse.success) {
               content = logResponse.log || 'Log endpoint returned success but no log content';
             } else if (logResponse && logResponse.log) {
-              content = logResponse.log;
             } else {
</code_context>

<issue_to_address>
**issue (bug_risk):** The `else if (logResponse && logResponse.log)` branch is now a no-op, so valid log content is ignored.

Previously this branch assigned `content = logResponse.log;`. Now it does nothing, so when `logResponse.success` is false but `logResponse.log` exists, `content` incorrectly remains the fallback string. Consider restoring the assignment:

```js
} else if (logResponse && logResponse.log) {
  content = logResponse.log;
} else {
  content = `Task Log for ${taskId}...`;
}
```
</issue_to_address>

### Comment 2
<location> `frontend/src/pages/Logs.js:326` </location>
<code_context>
               metadata: {
-                status: task.status,
+                status: task.status || task.state,
                 tesInstance: task.tes_name || 'Unknown'
               }
             });
</code_context>

<issue_to_address>
**suggestion:** Duplicated `tesInstance` field inside and outside `metadata` may cause confusion or inconsistent access patterns.

In the error case you’re now adding both `metadata.tesInstance` and a top-level `tesInstance`, while the success path only uses `metadata.tesInstance`. This inconsistency can confuse consumers of `allLogs`. Consider keeping `tesInstance` only in `metadata` and removing the top-level property here.

Suggested implementation:

```javascript
            const taskId = task.task_id || task.id;
            allLogs.push({
              id: taskId,
              type: 'task',

```

```javascript
              id: taskId,
              type: 'task',

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the task management overview with sortable columns and updates the logs view so that newly run demo tasks (from the main task list/dashboard) are correctly surfaced in the Logs page with richer metadata.

Changes:

  • Adds client-side sorting for Tasks by ID, Name, Status, TES Instance, and Created columns (defaulting to newest-first by creation time) while integrating with the existing search filter.
  • Updates the Logs page to pull recent tasks from dashboardData.tasks instead of submitted_tasks, handling both task_id and id shapes and enriching fallback log content with more task details.
  • Adjusts log construction and console diagnostics to better reflect the new data sources and task representations.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
frontend/src/pages/Tasks.js Introduces sortable table headers and a memoized sortTasks function to provide ascending/descending sorting across all task columns while preserving search and health filtering.
frontend/src/pages/Logs.js Switches the Logs view to use dashboardData.tasks, supports both task_id and id, fetches more recent tasks, and enriches log entries and fallbacks for both successful and failed log fetches.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


if (logResponse && logResponse.success) {
content = logResponse.log || 'Log endpoint returned success but no log content';
} else if (logResponse && logResponse.log) {
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else if (logResponse && logResponse.log) branch is now empty, so when getTaskLogs returns a response where success is false but log is present, the log content is silently discarded and the fallback summary is used instead. This regresses the previous behavior (where content was set from logResponse.log in this case) and can hide useful log details; consider assigning content from logResponse.log in this branch.

Suggested change
} else if (logResponse && logResponse.log) {
} else if (logResponse && logResponse.log) {
content = logResponse.log;

Copilot uses AI. Check for mistakes.
Comment on lines +341 to +342
},
tesInstance: task.tes_name || 'Unknown'
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the error path for loading task logs, the pushed log object includes a top-level tesInstance field in addition to metadata.tesInstance, whereas the rest of the code (and filterLogs) only uses metadata.tesInstance. This redundant field makes the log object shape inconsistent across code paths and can cause confusion for future maintainers; consider removing the extra top-level tesInstance or standardizing on a single location.

Suggested change
},
tesInstance: task.tes_name || 'Unknown'
}

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ninsch3000
Copy link

Only reviewed descriptions and UI screenshots: looks good to me. If all Copilot suggestions have been addressed this should be good to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants