Skip to content

Show deactivated DAG state in the UI (#63800)#64374

Closed
deepujain wants to merge 5 commits into
apache:mainfrom
deepujain:fix-63800-dag-deactivation-indicator
Closed

Show deactivated DAG state in the UI (#63800)#64374
deepujain wants to merge 5 commits into
apache:mainfrom
deepujain:fix-63800-dag-deactivation-indicator

Conversation

@deepujain

@deepujain deepujain commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

Summary

When a DAG becomes stale or deactivated, the UI still shows active-oriented controls like the pause toggle, parse action, and next-run information. This change makes the deactivated state explicit by showing a badge and hiding controls or stats that imply the DAG is still schedulable.

Changes

  • airflow-core/src/airflow/ui/src/components/DagDeactivatedBadge.tsx -- added a reusable badge component for stale/deactivated DAGs.
  • airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx -- shows the deactivated badge for stale DAGs, hides the misleading next-run stat, and removes the parse action for stale DAGs.
  • airflow-core/src/airflow/ui/src/layouts/Details/DagBreadcrumb.tsx -- shows the deactivated badge in the breadcrumb instead of the pause toggle for stale DAGs.
  • airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json -- adds the deactivated badge label.
  • airflow-core/src/airflow/ui/src/pages/Dag/Header.test.tsx -- adds a regression test covering the stale DAG header behavior, including hiding the stale-only parse action.

Test plan

  • npm run test -- Header.test.tsx
  • npx eslint src/components/DagDeactivatedBadge.tsx src/pages/Dag/Header.tsx src/layouts/Details/DagBreadcrumb.tsx src/layouts/Details/DetailsLayout.tsx src/pages/Dag/Header.test.tsx
  • CI passes

Evidence it works

  • The focused Vitest run passed locally with 2 passed test files and 3 passed tests, including the stale-DAG regression that now verifies the parse action is hidden.
  • The changed UI files pass focused eslint checks.

Fixes #63800

@deepujain

Copy link
Copy Markdown
Contributor Author

Pushed the UI update for stale DAGs. Local validation covered the new header regression test, focused eslint on the changed files, and a full UI build, so the branch now shows the deactivated state explicitly instead of active-looking controls.

@kalluripradeep kalluripradeep left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good UX improvement. The e2e tests are failing on all three browsers (Chromium, Firefox, WebKit) and static checks too — probably worth investigating those before this is ready to merge.

@deepujain deepujain force-pushed the fix-63800-dag-deactivation-indicator branch from 610738d to e209c4d Compare March 29, 2026 01:39
@deepujain

Copy link
Copy Markdown
Contributor Author

Validation update after rebasing this PR on main:

  • I fixed the branch-specific static-check failure in Header.test.tsx by updating the stale DAG mock to match the current DAGDetailsResponse shape after the rebase.
  • Local checks rerun and passing:
    • npm run test -- Header.test.tsx
    • npx eslint src/components/DagDeactivatedBadge.tsx src/pages/Dag/Header.tsx src/layouts/Details/DagBreadcrumb.tsx src/layouts/Details/DetailsLayout.tsx src/pages/Dag/Header.test.tsx
    • pnpm exec tsc --noEmit -p tsconfig.app.json
  • I force-pushed the existing PR branch so CI reruns on the rebased code.

On the last failing run before this push, the browser e2e failures were in tests/e2e/specs/home-dashboard.spec.ts across Chromium / Firefox / WebKit rather than in the DAG details flow touched here, so they looked unrelated to this UX change. The fresh run from this push should confirm that with the current branch state.

@deepujain

Copy link
Copy Markdown
Contributor Author

Follow-up after investigating the current failing checks:

  • I found one branch-specific regression in this change set: on stale DAG detail pages I had also hidden the manual Trigger DAG button in DetailsLayout, which is broader than the intended UX change. This push restores the trigger entry point while keeping the deactivated badge and hiding the stale-only pause / next-run affordances.
  • I also fixed the formatting drift on the touched UI files so the local static checks are clean again.

Local validation rerun on this head:

  • npm run test -- Header.test.tsx
  • pnpm exec eslint src/components/DagDeactivatedBadge.tsx src/layouts/Details/DagBreadcrumb.tsx src/layouts/Details/DetailsLayout.tsx src/pages/Dag/Header.tsx src/pages/Dag/Header.test.tsx
  • pnpm exec tsc --noEmit -p tsconfig.app.json
  • pnpm exec prettier --write src/components/DagDeactivatedBadge.tsx src/layouts/Details/DagBreadcrumb.tsx src/layouts/Details/DetailsLayout.tsx src/pages/Dag/Header.tsx src/pages/Dag/Header.test.tsx public/i18n/locales/en/dag.json

I force-pushed the existing PR branch so CI reruns on this narrower behavior. The previous Chromium / Firefox failures were still broad (backfill, requiredAction, xcoms, and task-instance flows), so this rerun should tell us whether the stale-DAG action suppression was part of that fallout or whether there is still unrelated noise in those jobs.

@deepujain

Copy link
Copy Markdown
Contributor Author

Quick CI follow-up: on the last run after the UI fix, Chromium UI e2e, Firefox UI e2e, and CI image checks / Static checks all passed. The only remaining red check was WebKit UI e2e.

I checked the WebKit log before rerunning. The remaining failures were in requiredAction.spec.ts and xcoms.spec.ts, and the log was no longer pointing at the stale-DAG header/details behavior changed in this PR. I cannot rerun the workflow directly via gh in this repo without admin rights, so I pushed this empty commit to trigger a fresh run on the same code and get a clean signal on that last browser-specific failure.

@pierrejeambrun pierrejeambrun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we also hide the 'trigger dag button' ? The description mentions that but isn't actually implementing it.

Suggestion: Header Actions Not Addressed
For a stale DAG, the header still shows Parse DAG and Delete DAG buttons. "Parse" in particular is misleading for a stale DAG (the file doesn't exist anymore). The PR should consider hiding or disabling ParseDagButton for stale DAGs as well, since parsing a DAG that has no source file doesn't make sense.

Suggestion: DAGs List Page isn't addressed and other TogglePause places too

Comment thread airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
Comment on lines +113 to +124
if (!dag?.is_stale) {
stats.splice(2, 0, {
label: translate("dagDetails.nextRun"),
value: Boolean(dag?.next_dagrun_run_after) ? (
<DagRunInfo
logicalDate={dag?.next_dagrun_logical_date}
runAfter={dag?.next_dagrun_run_after as string}
/>
) : undefined,
});
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

you can just use the spread operator her to not have to splice. ...(!dag?.is_stale: [], [])

@deepujain

Copy link
Copy Markdown
Contributor Author

Addressed the review points on this branch:

  • removed the unrelated DetailsLayout.tsx diff from the PR
  • updated the header to hide ParseDagButton for stale DAGs
  • refactored the stale/non-stale nextRun stat assembly to use a spread instead of splice
  • updated the PR description so it no longer claims a trigger-button change that this PR does not implement

I kept the code change scoped to the stale DAG detail/header path from the original issue report rather than broadening this PR into the DAG list views.

Local validation on this head:

  • npm run test -- Header.test.tsx
    Result: 2 passed test files / 3 passed tests
  • pnpm exec eslint src/pages/Dag/Header.tsx src/pages/Dag/Header.test.tsx src/layouts/Details/DagBreadcrumb.tsx src/layouts/Details/DetailsLayout.tsx src/components/DagDeactivatedBadge.tsx
    Result: passed

Pushed in c4c0ebbe13.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 makes “stale/deactivated” DAGs explicit in the UI by adding a deactivated badge and hiding controls/stats that imply the DAG is still schedulable.

Changes:

  • Added a reusable DagDeactivatedBadge component and corresponding i18n string.
  • Updated the DAG header and breadcrumb to show the badge and hide pause/parse/next-run UI for stale DAGs.
  • Added a regression test for stale DAG behavior in the DAG header.

Reviewed changes

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

Show a summary per file
File Description
airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx Conditionally hides “Next run” and parse action for stale DAGs; shows deactivated badge instead of pause toggle.
airflow-core/src/airflow/ui/src/pages/Dag/Header.test.tsx Adds a regression test for stale DAG UI behavior in the header.
airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx Removes run-after date filter local-storage state/props; simplifies useLocalStorage typing usage.
airflow-core/src/airflow/ui/src/layouts/Details/DagBreadcrumb.tsx Shows deactivated badge in breadcrumb for stale DAGs instead of pause toggle.
airflow-core/src/airflow/ui/src/components/DagDeactivatedBadge.tsx Introduces new badge component backed by i18n key.
airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json Adds the “Deactivated” label under header.status.deactivated.

Comment thread airflow-core/src/airflow/ui/src/pages/Dag/Header.test.tsx Outdated
Comment thread airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
Comment thread airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
Comment thread airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
Comment thread airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx Outdated
Comment thread airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx Outdated
Comment thread airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx Outdated
@deepujain

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up on top of the earlier review pass. The main fix here was restoring the runAfterGte / runAfterLte wiring in DetailsLayout, because the earlier partial revert removed that state but still left the grid panel depending on it, which is what the local static checks were tripping over; I also tightened the stale-DAG header checks and made the new test assert through the resolved i18n strings instead of raw keys. Local validation on this branch state: npm run test -- Header.test.tsx, focused eslint on the touched UI files, and pnpm exec tsc --noEmit -p tsconfig.app.json all passed. I kept the scope on the stale DAG details/header path here rather than expanding this PR into the other trigger/toggle locations.

@potiuk potiuk added the ready for maintainer review Set after triaging when all criteria pass. label Apr 2, 2026

@pierrejeambrun pierrejeambrun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That's a nice addition. We should probably gray out the 'trigger' button too but that's not straightforward since we do not have that information at the DetailsLayout level.

@pierrejeambrun pierrejeambrun force-pushed the fix-63800-dag-deactivation-indicator branch from ca3e5c2 to 4469eb7 Compare April 3, 2026 14:24
@pierrejeambrun

pierrejeambrun commented Apr 3, 2026

Copy link
Copy Markdown
Member

I just rebased the branch to remove unrelated CI failure.

Can you fix the formatting for: (and double check lint UI)

const nextRunStat =
-    isStale
-      ? []
-      : [
-          {
-            label: translate("dagDetails.nextRun"),
-            value: Boolean(dag?.next_dagrun_run_after) ? (
-              <DagRunInfo
-                logicalDate={dag?.next_dagrun_logical_date}
-                runAfter={dag?.next_dagrun_run_after as string}
-              />
-            ) : undefined,
-          },
-        ];
+  const nextRunStat = isStale
+    ? []
+    : [
+        {
+          label: translate("dagDetails.nextRun"),
+          value: Boolean(dag?.next_dagrun_run_after) ? (
+            <DagRunInfo
+              logicalDate={dag?.next_dagrun_logical_date}
+              runAfter={dag?.next_dagrun_run_after as string}
+            />
+          ) : undefined,
+        },
+      ];

CI is complaining

@pierrejeambrun

pierrejeambrun commented Apr 3, 2026

Copy link
Copy Markdown
Member

In a follow up we could add a 'tooltip' to the deactivated badge to explain what it means and why we see that. "Dag was marked as stale, probably because the dag file was removed etc..."

Screenshot 2026-04-03 at 16 26 17

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

Labels

area:translations area:UI Related to UI/UX. For Frontend Developers. ready for maintainer review Set after triaging when all criteria pass. translation:default

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deactivating an active DAG has no deactivation indicator in UI

5 participants