diff --git a/inc/Core/Admin/Pages/Jobs/assets/react/components/JobsTable.jsx b/inc/Core/Admin/Pages/Jobs/assets/react/components/JobsTable.jsx index 3df73a698..c5811c32d 100644 --- a/inc/Core/Admin/Pages/Jobs/assets/react/components/JobsTable.jsx +++ b/inc/Core/Admin/Pages/Jobs/assets/react/components/JobsTable.jsx @@ -45,9 +45,15 @@ const formatStatus = ( status ) => { }; /** - * Determine if a job is a batch parent from engine_data. + * Determine if a job has child jobs (batch parent or any parent). + * Uses child_count from the DB query, falls back to engine_data batch flag. */ -const isBatchParent = ( job ) => { +const hasChildren = ( job ) => { + // Prefer the child_count from the SQL subquery (most reliable). + if ( job.child_count !== undefined && parseInt( job.child_count, 10 ) > 0 ) { + return true; + } + // Fallback: check engine_data for batch flag. if ( ! job.engine_data ) { return false; } @@ -207,7 +213,7 @@ const ChildRows = ( { parentJobId } ) => { * Single job row — handles expand/collapse for batch parents. */ const JobRow = ( { job, isExpanded, onToggle } ) => { - const isBatch = isBatchParent( job ); + const isBatch = hasChildren( job ); return ( <> diff --git a/inc/Core/Database/Jobs/JobsOperations.php b/inc/Core/Database/Jobs/JobsOperations.php index 5996a628a..71f49d9d5 100644 --- a/inc/Core/Database/Jobs/JobsOperations.php +++ b/inc/Core/Database/Jobs/JobsOperations.php @@ -314,17 +314,20 @@ public function get_jobs_for_list_table( array $args ): array { // Build the full query // Note: orderby is validated above, so safe to interpolate // For direct execution jobs, LEFT JOINs will return NULL for pipeline_name/flow_name + // JOIN uses j.pipeline_id (varchar) directly against CAST of p.pipeline_id (int) to varchar + // for index-friendly matching on the jobs table side. // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber $query = $this->wpdb->prepare( - "SELECT j.*, p.pipeline_name, f.flow_name + "SELECT j.*, p.pipeline_name, f.flow_name, + (SELECT COUNT(*) FROM %i c WHERE c.parent_job_id = j.job_id) AS child_count FROM %i j - LEFT JOIN %i p ON j.pipeline_id = CAST(p.pipeline_id AS CHAR) - LEFT JOIN %i f ON j.flow_id = CAST(f.flow_id AS CHAR) + LEFT JOIN %i p ON j.pipeline_id = p.pipeline_id + LEFT JOIN %i f ON j.flow_id = f.flow_id {$where_sql} ORDER BY {$orderby} {$order} LIMIT %d OFFSET %d", array_merge( - array( $this->table_name, $pipelines_table, $flows_table ), + array( $this->table_name, $this->table_name, $pipelines_table, $flows_table ), $where_values, array( $per_page, $offset ) )