From 2dbd07367d90538c4c01881baab82b4dcc6b5f51 Mon Sep 17 00:00:00 2001 From: Chandrasekharan M Date: Thu, 28 May 2026 15:44:30 +0530 Subject: [PATCH 1/3] [FIX] Show alert with execution-logs link when a workflow is run The old WebSocket-based progress updates on the Agency page no longer fire, leaving the UI silent after a workflow run is triggered. Surface a sticky info notification with a react-router link to the execution's logs page so the user can navigate there (browser-back returns to the workflow page via SPA history). Extracts a shared NotificationIdLine component so the new Execution ID and the existing Request ID render through one renderer, and generalises the related CSS class to .notification-id-line. --- frontend/src/App.jsx | 35 ++++++++++++------- .../src/components/agency/agency/Agency.jsx | 10 ++++++ .../notification/NotificationIdLine.jsx | 31 ++++++++++++++++ frontend/src/index.css | 14 +++++--- frontend/src/store/alert-store.js | 1 + 5 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 frontend/src/components/notification/NotificationIdLine.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 149347f18f..ce7a94103e 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,10 +1,11 @@ -import { Button, ConfigProvider, notification, Typography, theme } from "antd"; +import { Button, ConfigProvider, notification, theme } from "antd"; import axios from "axios"; import { useEffect } from "react"; import { HelmetProvider } from "react-helmet-async"; import { BrowserRouter } from "react-router-dom"; import { GenericLoader } from "./components/generic-loader/GenericLoader"; import CustomMarkdown from "./components/helpers/custom-markdown/CustomMarkdown.jsx"; +import { NotificationIdLine } from "./components/notification/NotificationIdLine.jsx"; import { PageTitle } from "./components/widgets/page-title/PageTitle.jsx"; import { THEME } from "./helpers/GetStaticData.js"; import { attachRequestIdInterceptor } from "./helpers/requestId.js"; @@ -63,20 +64,22 @@ function App() { const showRequestId = alertDetails?.type === "error" && alertDetails?.requestId; + const showExecutionId = Boolean(alertDetails?.executionId); const description = ( <> + {showExecutionId && ( + + )} {showRequestId && ( -
- Request ID:{" "} - - {alertDetails?.requestId} - -
+ )} ); @@ -90,8 +93,14 @@ function App() { key: alertDetails?.key, }); - const logMessage = showRequestId - ? `${alertDetails.content}\nRequest ID: \`${alertDetails.requestId}\`` + const logSuffix = [ + showExecutionId && `Execution ID: \`${alertDetails.executionId}\``, + showRequestId && `Request ID: \`${alertDetails.requestId}\``, + ] + .filter(Boolean) + .join("\n"); + const logMessage = logSuffix + ? `${alertDetails.content}\n${logSuffix}` : alertDetails.content; pushLogMessages([ diff --git a/frontend/src/components/agency/agency/Agency.jsx b/frontend/src/components/agency/agency/Agency.jsx index de90e8d136..5fe5ec3a90 100644 --- a/frontend/src/components/agency/agency/Agency.jsx +++ b/frontend/src/components/agency/agency/Agency.jsx @@ -778,6 +778,16 @@ function Agency() { const execIdValue = initialRes?.data?.execution_id; setExecutionId(execIdValue); + if (execIdValue && !isStepExecution) { + // Live progress on this page is stale; point users at the logs page. + setAlertDetails({ + type: "info", + title: "Workflow run started", + content: `[View logs](/logs/WF/${execIdValue}) to track progress`, + executionId: execIdValue, + duration: 0, + }); + } body["execution_id"] = execIdValue; if (isStepExecution) { body["execution_action"] = wfExecutionTypes[executionAction]; diff --git a/frontend/src/components/notification/NotificationIdLine.jsx b/frontend/src/components/notification/NotificationIdLine.jsx new file mode 100644 index 0000000000..7e7739ddf8 --- /dev/null +++ b/frontend/src/components/notification/NotificationIdLine.jsx @@ -0,0 +1,31 @@ +import { Typography } from "antd"; +import PropTypes from "prop-types"; + +function NotificationIdLine({ label, value, stacked = false }) { + if (!value) { + return null; + } + const className = stacked + ? "notification-id-line notification-id-line--stacked" + : "notification-id-line"; + return ( +
+ {label}: + + {value} + +
+ ); +} + +NotificationIdLine.propTypes = { + label: PropTypes.string.isRequired, + value: PropTypes.string, + stacked: PropTypes.bool, +}; + +export { NotificationIdLine }; diff --git a/frontend/src/index.css b/frontend/src/index.css index aa670e91d8..023b47e579 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -252,12 +252,12 @@ body { z-index: 2000; } -.notification-request-id, -.notification-request-id__value { +.notification-id-line, +.notification-id-line__value { font-size: 12px; } -.notification-request-id { +.notification-id-line { margin-top: 8px; display: flex; align-items: center; @@ -265,6 +265,12 @@ body { gap: 4px; } -.notification-request-id__value { +.notification-id-line--stacked { + flex-direction: column; + align-items: flex-start; + gap: 2px; +} + +.notification-id-line__value { word-break: break-all; } diff --git a/frontend/src/store/alert-store.js b/frontend/src/store/alert-store.js index 25827813ab..e957a0a8ba 100644 --- a/frontend/src/store/alert-store.js +++ b/frontend/src/store/alert-store.js @@ -14,6 +14,7 @@ const STORE_VARIABLES = { duration: DEFAULT_DURATION, key: null, requestId: null, + executionId: null, }, }; From caa9b4a87c054e1c030d3183ae7ad13689a5a8c1 Mon Sep 17 00:00:00 2001 From: Chandrasekharan M Date: Thu, 28 May 2026 15:55:06 +0530 Subject: [PATCH 2/3] [FIX] Generic back navigation from execution logs; drop duplicate back button Adds useBackNavigation hook so any page that links to the execution logs page returns to where the user came from. Priority: 1. location.state.from (explicit caller hint; restores scroll state) 2. navigate(-1) when SPA history exists (covers markdown links in alerts and any future linker that didn't pass state) 3. fallback path (deep link / refresh) Wires the ToolNavBar back button on ExecutionLogs through the hook and removes the duplicate back button inside DetailedLogs (the cameFromDashboard branch is subsumed; RecentActivity now passes a real path in state.from). --- .../logging/detailed-logs/DetailedLogs.jsx | 20 +-------- .../logging/execution-logs/ExecutionLogs.jsx | 20 +++------ .../metrics-dashboard/RecentActivity.jsx | 2 +- frontend/src/hooks/useBackNavigation.js | 41 +++++++++++++++++++ 4 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 frontend/src/hooks/useBackNavigation.js diff --git a/frontend/src/components/logging/detailed-logs/DetailedLogs.jsx b/frontend/src/components/logging/detailed-logs/DetailedLogs.jsx index b7870942d7..3ff0034238 100644 --- a/frontend/src/components/logging/detailed-logs/DetailedLogs.jsx +++ b/frontend/src/components/logging/detailed-logs/DetailedLogs.jsx @@ -1,5 +1,4 @@ import { - ArrowLeftOutlined, CalendarOutlined, ClockCircleOutlined, CloseCircleFilled, @@ -24,12 +23,11 @@ import { } from "antd"; import PropTypes from "prop-types"; import { useEffect, useRef, useState } from "react"; -import { useLocation, useNavigate, useParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; import { useExceptionHandler } from "../../../hooks/useExceptionHandler"; import { useAlertStore } from "../../../store/alert-store"; -import { useSessionStore } from "../../../store/session-store"; import "./DetailedLogs.css"; import { formattedDateTime, @@ -93,12 +91,8 @@ const DetailedLogs = () => { const axiosPrivate = useAxiosPrivate(); const { setAlertDetails } = useAlertStore(); const handleException = useExceptionHandler(); - const navigate = useNavigate(); - const location = useLocation(); - const { sessionDetails } = useSessionStore(); const { getUrl } = useRequestUrl(); const copyToClipboard = useCopyToClipboard(); - const cameFromDashboard = location.state?.from === "dashboard"; const [executionDetails, setExecutionDetails] = useState(); const [executionFiles, setExecutionFiles] = useState(); @@ -460,18 +454,6 @@ const DetailedLogs = () => {
-