diff --git a/inc/Core/Admin/Pages/Jobs/assets/css/jobs-page.css b/inc/Core/Admin/Pages/Jobs/assets/css/jobs-page.css
index b5d4c41fc..eb72d41da 100644
--- a/inc/Core/Admin/Pages/Jobs/assets/css/jobs-page.css
+++ b/inc/Core/Admin/Pages/Jobs/assets/css/jobs-page.css
@@ -83,16 +83,29 @@
/* Table Column Widths */
.datamachine-col-job-id {
- width: 80px;
+ width: 70px;
+}
+
+.datamachine-col-pipeline,
+.datamachine-col-flow {
+ width: 140px;
+}
+
+.datamachine-col-label {
+ /* Flexible — takes remaining space */
+}
+
+.datamachine-col-label-cell {
+ word-break: break-word;
}
.datamachine-col-status {
- width: 100px;
+ width: 180px;
}
.datamachine-col-created,
.datamachine-col-completed {
- width: 140px;
+ width: 130px;
}
/* Job Status Colors - now using shared classes from root.css:
@@ -102,6 +115,24 @@
* .datamachine-status--neutral
*/
+/* Status detail (compound status reason) */
+.datamachine-status-detail {
+ display: block;
+ font-size: 11px;
+ color: #646970;
+ margin-top: 2px;
+ line-height: 1.3;
+ word-break: break-word;
+}
+
+/* Pipeline/Flow cell styling */
+.datamachine-col-pipeline,
+.datamachine-col-flow {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
/* Modal Styles */
@@ -273,6 +304,8 @@
gap: 15px;
}
+ .datamachine-col-label,
+ .datamachine-col-label-cell,
.datamachine-col-created,
.datamachine-col-completed {
display: none;
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 c5811c32d..4f95f397c 100644
--- a/inc/Core/Admin/Pages/Jobs/assets/react/components/JobsTable.jsx
+++ b/inc/Core/Admin/Pages/Jobs/assets/react/components/JobsTable.jsx
@@ -38,10 +38,31 @@ const formatStatus = ( status ) => {
if ( ! status ) {
return __( 'Unknown', 'data-machine' );
}
- return (
+ // Show base status as the label, full detail on hover via title attr.
+ const formatted =
status.charAt( 0 ).toUpperCase() +
- status.slice( 1 ).replace( /_/g, ' ' )
- );
+ status.slice( 1 ).replace( /_/g, ' ' );
+ return formatted;
+};
+
+/**
+ * Extract the base status (before " - " detail separator).
+ */
+const getBaseStatus = ( status ) => {
+ if ( ! status ) {
+ return '';
+ }
+ return status.split( ' - ' )[ 0 ];
+};
+
+/**
+ * Get the detail portion of a compound status (after " - ").
+ */
+const getStatusDetail = ( status ) => {
+ if ( ! status || ! status.includes( ' - ' ) ) {
+ return null;
+ }
+ return status.split( ' - ' ).slice( 1 ).join( ' - ' );
};
/**
@@ -163,7 +184,7 @@ const ChildRows = ( { parentJobId } ) => {
if ( isLoading ) {
return (
- |
+ |
@@ -175,11 +196,24 @@ const ChildRows = ( { parentJobId } ) => {
);
}
- if ( isError || ! children || children.length === 0 ) {
+ if ( isError ) {
+ return (
+
+ |
+ { __( 'Failed to load child jobs.', 'data-machine' ) }
+ |
+
+ );
+ }
+
+ if ( ! children || children.length === 0 ) {
return (
- |
- { __( 'No child jobs found.', 'data-machine' ) }
+ |
+ { __(
+ 'Child jobs were scheduled but have not been recorded yet.',
+ 'data-machine'
+ ) }
|
);
@@ -194,14 +228,26 @@ const ChildRows = ( { parentJobId } ) => {
{ child.job_id }
|
- { child.display_label ||
- child.label ||
- __( 'Child job', 'data-machine' ) }
+ { child.pipeline_name || '\u2014' }
|
-
- { formatStatus( child.status ) }
+ { child.flow_name || '\u2014' }
+ |
+
+ { child.label || '\u2014' }
+ |
+
+
+ { formatStatus( getBaseStatus( child.status ) || child.status ) }
+ { getStatusDetail( child.status ) && (
+
+ { getStatusDetail( child.status ) }
+
+ ) }
|
{ child.created_at_display || '' } |
{ child.completed_at_display || '' } |
@@ -212,6 +258,34 @@ const ChildRows = ( { parentJobId } ) => {
/**
* Single job row — handles expand/collapse for batch parents.
*/
+/**
+ * Format pipeline display value.
+ * Shows name for DB pipelines, "Direct" for direct execution, em dash for null.
+ */
+const formatPipeline = ( job ) => {
+ if ( job.pipeline_name ) {
+ return job.pipeline_name;
+ }
+ if ( job.pipeline_id === 'direct' ) {
+ return __( 'Direct', 'data-machine' );
+ }
+ return '\u2014';
+};
+
+/**
+ * Format flow display value.
+ * Shows name for DB flows, "Direct" for direct execution, em dash for null.
+ */
+const formatFlow = ( job ) => {
+ if ( job.flow_name ) {
+ return job.flow_name;
+ }
+ if ( job.flow_id === 'direct' ) {
+ return __( 'Direct', 'data-machine' );
+ }
+ return '\u2014';
+};
+
const JobRow = ( { job, isExpanded, onToggle } ) => {
const isBatch = hasChildren( job );
@@ -238,17 +312,27 @@ const JobRow = ( { job, isExpanded, onToggle } ) => {
- { job.display_label ||
- job.label ||
- ( job.pipeline_name && job.flow_name
- ? `${ job.pipeline_name } \u2192 ${ job.flow_name }`
- : __( 'Unknown', 'data-machine' ) ) }
+ { formatPipeline( job ) }
+ |
+
+ { formatFlow( job ) }
+ |
+
+ { job.label || '\u2014' }
{ isBatch && }
|
-
- { formatStatus( job.status ) }
+
+ { formatStatus( getBaseStatus( job.status ) || job.status ) }
+ { getStatusDetail( job.status ) && (
+
+ { getStatusDetail( job.status ) }
+
+ ) }
|
{ job.created_at_display || '' } |
{ job.completed_at_display || '' } |
@@ -307,15 +391,23 @@ const JobsTable = ( { jobs, isLoading, isError, error } ) => {
{ __( 'Job ID', 'data-machine' ) }
|
- { __( 'Source', 'data-machine' ) } |
+
+ { __( 'Pipeline', 'data-machine' ) }
+ |
+
+ { __( 'Flow', 'data-machine' ) }
+ |
+
+ { __( 'Label', 'data-machine' ) }
+ |
{ __( 'Status', 'data-machine' ) }
|
- { __( 'Created At', 'data-machine' ) }
+ { __( 'Created', 'data-machine' ) }
|
- { __( 'Completed At', 'data-machine' ) }
+ { __( 'Completed', 'data-machine' ) }
|