diff --git a/ui/src/components/atoms/StatusChip.tsx b/ui/src/components/atoms/StatusChip.tsx
index 0f235f6a7..de0088a2e 100644
--- a/ui/src/components/atoms/StatusChip.tsx
+++ b/ui/src/components/atoms/StatusChip.tsx
@@ -9,12 +9,12 @@ type Props = {
};
function StatusChip({ status, children }: Props) {
- const style = React.useMemo(() => {
+ const style = () => {
if (!status) {
return {};
}
return statusColorMapping[status] || {};
- }, [status]);
+ };
return ;
}
diff --git a/ui/src/components/molecules/Graph.tsx b/ui/src/components/molecules/Graph.tsx
index 5d5bd3b87..be96f02c5 100644
--- a/ui/src/components/molecules/Graph.tsx
+++ b/ui/src/components/molecules/Graph.tsx
@@ -50,6 +50,10 @@ const Graph: React.FC = ({
minHeight: '200px',
padding: '2em',
borderRadius: '0.5em',
+ background: `
+ linear-gradient(90deg, #f8fafc 1px, transparent 1px),
+ linear-gradient(180deg, #f8fafc 1px, transparent 1px)
+ `,
backgroundSize: '20px 20px',
};
@@ -88,7 +92,7 @@ const Graph: React.FC = ({
// Construct node label with icon if enabled
const icon = showIcons ? statusIcons[status] || '' : '';
- const label = `${icon} ${step.Name}`;
+ const label = `${icon} ${step.Name}`;
// Add node definition
dat.push(`${id}[${label}]${c};`);
@@ -134,24 +138,12 @@ const Graph: React.FC = ({
}
// Define node styles for different states with refined colors
- dat.push(
- 'classDef none color:#4a5568,fill:#f8fafc,stroke:#3b82f6,stroke-width:1.2px,white-space:nowrap,line-height:1.5'
- );
- dat.push(
- 'classDef running color:#4a5568,fill:#aaf2aa,stroke:#22c55e,stroke-width:1.2px,white-space:nowrap,line-height:1.5'
- );
- dat.push(
- 'classDef error color:#4a5568,fill:#fee2e2,stroke:#ef4444,stroke-width:1.2px,white-space:nowrap,line-height:1.5'
- );
- dat.push(
- 'classDef cancel color:#4a5568,fill:#fdf2f8,stroke:#ec4899,stroke-width:1.2px,white-space:nowrap,line-height:1.5'
- );
- dat.push(
- 'classDef done color:#4a5568,fill:#f0fdf4,stroke:#16a34a,stroke-width:1.2px,white-space:nowrap,line-height:1.5'
- );
- dat.push(
- 'classDef skipped color:#4a5568,fill:#f8fafc,stroke:#64748b,stroke-width:1.2px,white-space:nowrap,line-height:1.5'
- );
+ dat.push('classDef none fill:#f0f9ff,stroke:#93c5fd,color:#1e40af,stroke-width:1.2px,white-space:nowrap');
+ dat.push('classDef running fill:#f0fdf4,stroke:#86efac,color:#166534,stroke-width:1.2px,white-space:nowrap');
+ dat.push('classDef error fill:#fef2f2,stroke:#fca5a5,color:#aa1010,stroke-width:1.2px,white-space:nowrap');
+ dat.push('classDef cancel fill:#fdf2f8,stroke:#f9a8d4,color:#9d174d,stroke-width:1.2px,white-space:nowrap');
+ dat.push('classDef done fill:#f0fdf4,stroke:#86efac,color:#166534,stroke-width:1.2px,white-space:nowrap');
+ dat.push('classDef skipped fill:#f8fafc,stroke:#cbd5e1,color:#475569,stroke-width:1.2px,white-space:nowrap');
// Add custom link styles
dat.push(...linkStyles);
@@ -228,4 +220,4 @@ const graphStatusMap = {
[NodeStatus.Cancel]: ':::cancel',
[NodeStatus.Success]: ':::done',
[NodeStatus.Skipped]: ':::skipped',
-};
+};
\ No newline at end of file
diff --git a/ui/src/components/organizations/DAGStatus.tsx b/ui/src/components/organizations/DAGStatus.tsx
index 837142291..b788480e4 100644
--- a/ui/src/components/organizations/DAGStatus.tsx
+++ b/ui/src/components/organizations/DAGStatus.tsx
@@ -127,6 +127,7 @@ function DAGStatus({ DAG, name, refresh }: Props) {
type="status"
flowchart={flowchart}
onClickNode={onSelectStepOnGraph}
+ showIcons={DAG.Status.Status != SchedulerStatus.None}
>
) : (
diff --git a/ui/src/pages/dags/dag/index.tsx b/ui/src/pages/dags/dag/index.tsx
index 6e0dbef2e..25beb50e8 100644
--- a/ui/src/pages/dags/dag/index.tsx
+++ b/ui/src/pages/dags/dag/index.tsx
@@ -13,6 +13,10 @@ import DAGEditButtons from '../../../components/molecules/DAGEditButtons';
import LoadingIndicator from '../../../components/atoms/LoadingIndicator';
import { AppBarContext } from '../../../contexts/AppBarContext';
import useSWR from 'swr';
+import StatusChip from '../../../components/atoms/StatusChip';
+import { CalendarToday, TimerSharp } from '@mui/icons-material';
+import moment from 'moment-timezone';
+import { SchedulerStatus } from '../../../models';
type Params = {
name: string;
@@ -62,6 +66,21 @@ function DAGDetails() {
name: params.name,
};
+ const formatDuration = (startDate: string, endDate: string) => {
+ if (!startDate || !endDate) return '--';
+ const duration = moment.duration(moment(endDate).diff(moment(startDate)));
+ const hours = Math.floor(duration.asHours());
+ const minutes = duration.minutes();
+ const seconds = duration.seconds();
+
+ if (hours > 0) {
+ return `${hours}h ${minutes}m ${seconds}s`;
+ } else if (minutes > 0) {
+ return `${minutes}m ${seconds}s`;
+ }
+ return `${seconds}s`;
+ };
+
return (
+ {data.DAG?.Status?.Status != SchedulerStatus.None ? (
+
+ {data.DAG?.Status?.Status ? (
+
+ {data.DAG.Status.StatusText || ''}
+
+ ) : null}
+
+
+
+ {data?.DAG?.Status?.FinishedAt
+ ? moment(data.DAG.Status.FinishedAt).format(
+ 'MMM D, YYYY HH:mm:ss Z'
+ )
+ : '--'}
+
+
+
+
+ {data?.DAG?.Status?.FinishedAt
+ ? formatDuration(
+ data?.DAG?.Status?.StartedAt,
+ data?.DAG?.Status?.FinishedAt
+ )
+ : data?.DAG?.Status?.StartedAt
+ ? formatDuration(
+ data?.DAG?.Status?.StartedAt,
+ moment().toISOString()
+ )
+ : '--'}
+
+
+ ) : null}
+