You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ji...@apache.org on 2025/11/10 01:43:30 UTC

(ambari) branch frontend-refactor updated: AMBARI-26554: Ambari Web React: fix bugs in stack version and upgrade (#4084)

This is an automated email from the ASF dual-hosted git repository.

jialiang pushed a commit to branch frontend-refactor
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/frontend-refactor by this push:
     new 6b17929738 AMBARI-26554: Ambari Web React: fix bugs in stack version and upgrade (#4084)
6b17929738 is described below

commit 6b1792973893cd7180be9e3f625890bc72cfabd3
Author: Sandeep  Kumar <sk...@visa.com>
AuthorDate: Mon Nov 10 07:13:24 2025 +0530

    AMBARI-26554: Ambari Web React: fix bugs in stack version and upgrade (#4084)
---
 ambari-web/latest/src/Utils/Utility.ts             |  112 +-
 ambari-web/latest/src/api/VersionsApi.ts           |   38 +
 .../latest/src/components/NestedCollapse.tsx       |   37 +-
 .../latest/src/components/OperationProgress.tsx    |   19 +-
 ambari-web/latest/src/components/RepoModal.tsx     |  251 +++
 ambari-web/latest/src/components/Tooltip.tsx       |    2 +-
 ambari-web/latest/src/hooks/useUpgrade.ts          |   69 +-
 .../ClusterAdmin/StackAndVersions/ListVersion.tsx  | 1983 ++++++++++++--------
 .../ClusterAdmin/StackAndVersions/Upgrade.tsx      |  390 +++-
 .../screens/ClusterAdmin/StackAndVersions/types.ts |   66 +-
 ambari-web/latest/src/store/context.tsx            |   10 +
 11 files changed, 2052 insertions(+), 925 deletions(-)

diff --git a/ambari-web/latest/src/Utils/Utility.ts b/ambari-web/latest/src/Utils/Utility.ts
index 024f371b94..1239122351 100644
--- a/ambari-web/latest/src/Utils/Utility.ts
+++ b/ambari-web/latest/src/Utils/Utility.ts
@@ -22,7 +22,9 @@ import { detectUserTimezone, parseTimezones } from "./timezone";
 import DOMPurify from "isomorphic-dompurify";
 import parse from 'html-react-parser';
 import { t } from "i18next";
-import { faCogs, faGears, faCheck, faTimes, faPause, faClock } from "@fortawesome/free-solid-svg-icons";
+import { faCogs, faGears, faCheck, faPause, faClock, faMinus, faExclamationCircle, faShare } from "@fortawesome/free-solid-svg-icons";
+import modalManager from "../store/ModalManager";
+import { JSX } from "react";
 
 export const padNumber = (num: number) => (num < 10 ? `0${num}` : num);
 const components: any = {
@@ -547,7 +549,10 @@ export const getUpgradeDisplayName = (upgradeType: string) => {
   }
 }
 
-export function getIconObject(status: string) {
+export function getIconObject(status: string, onlyView: boolean) {
+  if(status === "ABORTED" && onlyView) {
+    return { icon: faMinus, color: "text-warning" };
+  }
   switch (status.toUpperCase()) {
     case "PENDING":
     case "QUEUED":
@@ -557,12 +562,111 @@ export function getIconObject(status: string) {
     case "COMPLETED":
       return { icon: faCheck, color: "text-success" };
     case "FAILED":
-      return { icon: faTimes, color: "text-danger" };
+      case "HOLDING_FAILED":
+      return { icon: faExclamationCircle, color: "text-danger" };
     case "ABORTED":
       return { icon: faPause, color: "text-ligth" };
+    case "HOLDING":
+    case "HOLDING_TIMEDOUT":
     case "TIMEDOUT":
       return { icon: faClock, color: "text-warning" };
+    case "SKIPPED_FAILED":
+      return { icon: faShare, color: "text-danger" };  
     default:
       return { icon: faPause, color: "text-light" };
   }
-}
\ No newline at end of file
+}
+
+export const initialOptions = [
+  { key: "ALL", values: ["ALL"], count: 0 },
+  {
+    key: "NOT INSTALLED",
+    values: ["INSTALL_FAILED", "INSTALLING", "NOT_REQUIRED"],
+    count: 0,
+  },
+  { key: "UPGRADE READY", values: ["UPGRADE_READY"], count: 0 },
+  { key: "CURRENT", values: ["CURRENT"], count: 0 },
+  { key: "INSTALLED", values: ["INSTALLED"], count: 0 },
+  {
+    key: "UPGRADE/DOWNGRADE IN PROGRESS",
+    values: ["Upgrade/Downgrade in Progress"],
+    count: 0,
+  },
+  { key: "READY TO FINALIZE", values: ["Ready to Finalize"], count: 0 },
+];
+
+export const initialUpgradeMethods = [
+  {
+    displayName: translate(
+      "admin.stackVersions.version.upgrade.upgradeOptions.RU.title"
+    ),
+    type: "ROLLING",
+    icon: "faDashboard",
+    description: translate(
+      "admin.stackVersions.version.upgrade.upgradeOptions.RU.description"
+    ),
+    selected: false,
+    allowed: true,
+    isCheckComplete: false,
+    isCheckRequestInProgress: false,
+    precheckResultsMessage: "",
+    preCheckResultsModalContent: null as JSX.Element | null,
+    precheckResultsTitle: "",
+    action: "",
+    isWizardRestricted: false,
+  },
+  {
+    displayName: translate(
+      "admin.stackVersions.version.upgrade.upgradeOptions.EU.title"
+    ),
+    type: "NON_ROLLING",
+    icon: "faBolt",
+    description: translate(
+      "admin.stackVersions.version.upgrade.upgradeOptions.EU.description"
+    ),
+    selected: false,
+    allowed: true,
+    isCheckComplete: false,
+    isCheckRequestInProgress: false,
+    precheckResultsMessage: "",
+    preCheckResultsModalContent: null as JSX.Element | null,
+    precheckResultsTitle: "",
+    action: "",
+    isWizardRestricted: false,
+  },
+  {
+    displayName: translate(
+      "admin.stackVersions.version.upgrade.upgradeOptions.HOU.title"
+    ),
+    type: "HOST_ORDERED",
+    icon: "faBolt",
+    description: "",
+    selected: false,
+    allowed: false,
+    isCheckComplete: false,
+    isCheckRequestInProgress: false,
+    precheckResultsMessage: "",
+    preCheckResultsModalContent: null as JSX.Element | null,
+    precheckResultsTitle: "",
+    action: "",
+    cantBeStarted: true,
+  },
+];
+
+export const showAlertModal = (header: any, body: any) => {
+  const modalProps = {
+    modalTitle: header,
+    modalBody: body,
+    onClose: () => {},
+    successCallback: () => {
+      modalManager.hide();
+    },
+    options: {
+      buttonSize: "sm" as "sm" | "lg" | undefined,
+      cancelableViaIcon: true,
+      cancelableViaBtn: false,
+      okButtonVariant: "primary",
+    },
+  };
+  modalManager.show(modalProps);
+};
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/VersionsApi.ts b/ambari-web/latest/src/api/VersionsApi.ts
index bff4207d70..5f0def0033 100644
--- a/ambari-web/latest/src/api/VersionsApi.ts
+++ b/ambari-web/latest/src/api/VersionsApi.ts
@@ -198,6 +198,44 @@ const VersionsApi = {
     });
     return response.data;
   },
+  validateRepos: async function name(
+    stack: string,
+    stackVersion: string,
+    os: string,
+    repo: string,
+    payload: { base_url: string; repo_name: string }
+  ) {
+    const url = `/stacks/${stack}/versions/${stackVersion}/operating_systems/${os}/repositories/${repo}?validate_only=true`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "POST",
+      data: { Repositories: payload },
+    });
+    return response.data;
+  },
+  saveRepoVersions: async function name(
+    stack: string,
+    stackVersion: string,
+    version_id: string,
+    payload: any
+  ) {
+    const url = `/stacks/${stack}/versions/${stackVersion}/repository_versions/${version_id}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "PUT",
+      data: payload,
+    });
+    return response.data;
+  },
+  updateUpgrade: async function (upgradeId: number, data: any, clusterName: string) {
+    const url = `/clusters/${clusterName}/upgrades/${upgradeId}`;
+    const response = await ambariApi.request({
+      url,
+      method: "PUT",
+      data,
+    });
+    return response.data;
+  }
 };
 
 export default VersionsApi;
diff --git a/ambari-web/latest/src/components/NestedCollapse.tsx b/ambari-web/latest/src/components/NestedCollapse.tsx
index 3b0393db41..4bc1ae1093 100644
--- a/ambari-web/latest/src/components/NestedCollapse.tsx
+++ b/ambari-web/latest/src/components/NestedCollapse.tsx
@@ -45,6 +45,7 @@ type NestedCollapseProps = {
   ) => Promise<void>;
   handleCopy: (text: string) => void;
   handleOpenInNewTab: (content: string) => void;
+  onlyView: boolean;
 };
 
 type NestedSubCollapseProps = {
@@ -60,6 +61,7 @@ type NestedSubCollapseProps = {
   ) => Promise<void>;
   handleCopy: (text: string) => void;
   handleOpenInNewTab: (content: string) => void;
+  onlyView: boolean;
 };
 
 const SubCollapse = ({
@@ -70,7 +72,8 @@ const SubCollapse = ({
   fetchTasks,
   fetchLogs,
   handleCopy,
-  handleOpenInNewTab
+  handleOpenInNewTab,
+  onlyView
 }: NestedSubCollapseProps) => {
   const [logsActiveKeys, setLogsActiveKeys] = useState<{
     [key: number]: boolean;
@@ -115,11 +118,11 @@ const SubCollapse = ({
                   aria-expanded={activeKeys.includes(eventKey)}
                 >
                   <div className="d-flex justify-content-between">
-                    { getIconObject(item.UpgradeItem.display_status) && (
+                    { getIconObject(item.UpgradeItem.display_status, onlyView) && (
                       <FontAwesomeIcon 
-                        icon={getIconObject(item.UpgradeItem.display_status).icon}
+                        icon={getIconObject(item.UpgradeItem.display_status, onlyView).icon}
                         size="lg"
-                        className={`me-2 ${getIconObject(item.UpgradeItem.display_status).color}`}
+                        className={`me-2 ${getIconObject(item.UpgradeItem.display_status, onlyView).color}`}
                       />
                     )}
                     <div>{item.UpgradeItem.context}</div>
@@ -153,11 +156,11 @@ const SubCollapse = ({
                                   )
                                 }
                               >
-                                { getIconObject(task?.status) ? (
+                                { getIconObject(task?.status, onlyView) ? (
                                   <FontAwesomeIcon 
-                                    icon={getIconObject(task?.status).icon}
+                                    icon={getIconObject(task?.status, onlyView).icon}
                                     size="lg"
-                                    className={`me-2 ${getIconObject(item.UpgradeItem.display_status).color}`}
+                                    className={`me-2 ${getIconObject(item.UpgradeItem.display_status, onlyView).color}`}
                                   />
                                   ) : null
                                 }
@@ -186,7 +189,7 @@ const SubCollapse = ({
                                               variant="link"
                                               onClick={() =>
                                                 handleCopy(
-                                                  task.logs?.Tasks?.output_log as any
+                                                  task.logs?.Tasks?.stdout as any
                                                 )
                                               }
                                             >
@@ -223,7 +226,7 @@ const SubCollapse = ({
                                               variant="link"
                                               onClick={() =>
                                                 handleCopy(
-                                                  task.logs?.Tasks?.error_log as any
+                                                  task.logs?.Tasks?.stderr as any
                                                 )
                                               }
                                             >
@@ -272,7 +275,8 @@ export default function NestedCollapse({
   fetchTasks,
   fetchLogs,
   handleCopy,
-  handleOpenInNewTab
+  handleOpenInNewTab,
+  onlyView
 }: NestedCollapseProps) {
   const handleToggle = (key: string) => {
     setActiveKeys((prevKeys: string[]) =>
@@ -292,18 +296,18 @@ export default function NestedCollapse({
                 <Button
                   className="custom-link"
                   variant="link"
-                  disabled={group.UpgradeGroup.display_status === "ABORTED"}
+                  disabled={!onlyView && group.UpgradeGroup.display_status === "ABORTED"}
                   onClick={() => handleToggle(eventKey)}
                   aria-controls={eventKey}
                   aria-expanded={activeKeys.includes(eventKey)}
                 >
 
                   <div className="d-flex justify-content-between">
-                    { getIconObject(group.UpgradeGroup.display_status) && (
+                    { getIconObject(group.UpgradeGroup.display_status, onlyView) && (
                       <FontAwesomeIcon 
-                        icon={getIconObject(group.UpgradeGroup.display_status).icon}
+                        icon={getIconObject(group.UpgradeGroup.display_status, onlyView).icon}
                         size="lg"
-                        className={`me-2 ${getIconObject(group.UpgradeGroup.display_status).color}`}
+                        className={`me-2 ${getIconObject(group.UpgradeGroup.display_status, onlyView).color}`}
                       />
                     )}
                     <div>{group.UpgradeGroup.title}</div>
@@ -323,7 +327,9 @@ export default function NestedCollapse({
                 <div id={eventKey}>
                   <Card.Body>
                     <SubCollapse
-                      items={[...group.upgrade_items].reverse()}
+                      items={[...group.upgrade_items].filter(item => 
+                        onlyView || (item.UpgradeItem.status !== "PENDING" && item.UpgradeItem.display_status !== "ABORTED")
+                      ).reverse()}
                       groupId={group.UpgradeGroup.group_id}
                       activeKeys={activeKeys}
                       setActiveKeys={setActiveKeys}
@@ -331,6 +337,7 @@ export default function NestedCollapse({
                       fetchLogs={fetchLogs}
                       handleCopy={handleCopy}
                       handleOpenInNewTab={handleOpenInNewTab}
+                      onlyView={onlyView}
                     />
                   </Card.Body>
                 </div>
diff --git a/ambari-web/latest/src/components/OperationProgress.tsx b/ambari-web/latest/src/components/OperationProgress.tsx
index 9467a390e0..3084abd49a 100644
--- a/ambari-web/latest/src/components/OperationProgress.tsx
+++ b/ambari-web/latest/src/components/OperationProgress.tsx
@@ -22,7 +22,7 @@ import { RequestApi } from "../api/requestApi";
 import { AppContext } from "../store/context";
 import { isFailed, isFinished } from "../Utils/Utility";
 import { ProgressStatus} from "../constants";
-import { Button, ProgressBar, Stack } from "react-bootstrap";
+import { Alert, Button, ProgressBar, Stack } from "react-bootstrap";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import {
   faCircleCheck,
@@ -45,6 +45,7 @@ type PropTypes = {
     }
   ];
   dispatch?: (operationsState: any) => void;
+  errorCallback?: (errorMsg: string) => void;
 };
 
 type OperationRequestResponse = {
@@ -62,6 +63,7 @@ function OperationsProgress({
   setCompletionStatus,
   operations,
   dispatch,
+  errorCallback
 }: PropTypes) {
   const [operationsState, setOperationsState] = useState(operations);
   const operationsRef = useRef(operations);
@@ -222,6 +224,21 @@ function OperationsProgress({
                   label={`${Math.floor(stage.progress)}%`}
                 />
               ) : null}
+
+              {has(operation, "error") &&
+                isFinished(operation.status) &&
+                (errorCallback ? (
+                  (errorCallback(
+                    operation.error ||
+                      "Error: An error occurred during the operation."
+                  ),
+                  null)
+                ) : (
+                  <Alert variant="danger" className="scrollable-h15 mt-3">
+                    {operation.error ||
+                      "Error: An error occurred during the operation."}
+                  </Alert>
+                ))}
             </Stack>
           );
         })}
diff --git a/ambari-web/latest/src/components/RepoModal.tsx b/ambari-web/latest/src/components/RepoModal.tsx
new file mode 100644
index 0000000000..e9faf4563a
--- /dev/null
+++ b/ambari-web/latest/src/components/RepoModal.tsx
@@ -0,0 +1,251 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Col, Form, Row } from "react-bootstrap";
+import Modal from "./Modal";
+import Tooltip from "./Tooltip";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
+import { useState } from "react";
+import VersionsApi from "../api/VersionsApi";
+import toast from "react-hot-toast";
+
+type PropTypes = {
+  isOpen: boolean;
+  onClose: () => void;
+  selectedStack: any;
+};
+
+function RepoModal({ isOpen, onClose, selectedStack }: PropTypes) {
+  const [repoUrls, setRepoUrls] = useState<{ [key: string]: string }>({});
+  const [skipRepoValidation, setSkipRepoValidation] = useState(false);
+  const [useRedhatSatellite, setUseRedhatSatellite] = useState(
+    !(selectedStack?.repository_versions?.[0]?.operating_systems?.[0]?.OperatingSystems?.ambari_managed_repositories ?? false)
+  );
+  const [validatingRepos, setValidatingRepos] = useState(false);
+  function handleRepoUrlChange(repoId: string, url: string) {
+    setRepoUrls((prev) => ({
+      ...prev,
+      [repoId]: url,
+    }));
+  }
+  function getRepoModalBody() {
+    return (
+      <div className="m-n2">
+        <div className="alert alert-info mb-3">
+          Provide Base URLs for the Operating Systems you are configuring.
+        </div>
+        <div className="repo-table">
+          <Row className="align-items-center py-3 border-bottom">
+            <Col md={2}>OS</Col>
+            <Col md={2}>Name</Col>
+            <Col md={8}>Base URL</Col>
+          </Row>
+          {selectedStack?.repository_versions?.[0]?.operating_systems?.map(
+            (os: any) => (
+              <div key={os.OperatingSystems.os_type}>
+                {os.repositories.map((repo: any, index: number) => (
+                  <Row
+                    className="align-items-center py-3 border-bottom"
+                    key={repo.Repositories.repo_id}
+                  >
+                    {index === 0 ? (
+                      <Col md={2}>{os.OperatingSystems.os_type}</Col>
+                    ) : (
+                      <Col md={2}></Col>
+                    )}
+                    <Col md={2}>{repo.Repositories.repo_name}</Col>
+                    <Col md={8}>
+                      <Form.Control
+                        type="text"
+                        defaultValue={repo.Repositories.base_url}
+                        disabled={useRedhatSatellite}
+                        onChange={(e) =>
+                          handleRepoUrlChange(
+                            repo.Repositories.repo_id,
+                            e.target.value
+                          )
+                        }
+                      />
+                    </Col>
+                  </Row>
+                ))}
+              </div>
+            )
+          )}
+        </div>
+        <div className="mt-3">
+          <Form>
+            <Form.Check
+              type="checkbox"
+              id="skipValidation"
+              checked={skipRepoValidation}
+              onChange={(e) => setSkipRepoValidation(e.target.checked)}
+              label={
+                <div className="d-flex align-items-center">
+                  Skip Repository Base URL validation (Advanced)
+                  <Tooltip
+                    message="Warning! This is for advanced users only. Use this option if you want to skip validation for Repository Base URLs."
+                    placement="right"
+                  >
+                    <FontAwesomeIcon className="ms-2" icon={faQuestionCircle} />
+                  </Tooltip>
+                </div>
+              }
+            />
+            <Form.Check
+              type="checkbox"
+              id="redhatSatellite"
+              checked={useRedhatSatellite}
+              onChange={(e) => setUseRedhatSatellite(e.target.checked)}
+              label={
+                <div className="d-flex align-items-center">
+                  Use RedHat Satellite/Spacewalk
+                  <Tooltip
+                    message="Disable distributed repositories and use RedHat Satellite/Spacewalk channels instead"
+                    placement="right"
+                  >
+                    <FontAwesomeIcon className="ms-2" icon={faQuestionCircle} />
+                  </Tooltip>
+                </div>
+              }
+            />
+          </Form>
+        </div>
+      </div>
+    );
+  }
+  async function saveRepositories(
+    stack: string,
+    stackVersion: string,
+    repoVersionId: string
+  ) {
+    try {
+      const operatingSystems =
+        selectedStack?.repository_versions[0].operating_systems;
+      if (!operatingSystems) return;
+
+      const payload = {
+        operating_systems: operatingSystems.map((os: any) => {
+          return {
+            OperatingSystems: {
+              os_type: os.OperatingSystems.os_type,
+              ambari_managed_repositories: !useRedhatSatellite,
+            },
+            repositories: os.repositories.map((repo: any) => {
+              const repoId = repo.Repositories.repo_id;
+              return {
+                Repositories: {
+                  base_url: repoUrls[repoId] || repo.Repositories.base_url,
+                  repo_id: repoId,
+                  repo_name: repo.Repositories.repo_name,
+                },
+              };
+            }),
+          };
+        }),
+      };
+
+      await VersionsApi.saveRepoVersions(
+        stack,
+        stackVersion,
+        repoVersionId,
+        payload
+      );
+      toast.success("Repositories saved successfully");
+      onClose();
+    } catch (err) {
+      const errorMessage = err instanceof Error ? err.message : String(err);
+      toast.error(`Failed to save repositories: ${errorMessage}`);
+    }
+  }
+  async function validateAndSaveRepos() {
+    if (!selectedStack) return;
+
+    setValidatingRepos(true);
+    const stack = selectedStack.ClusterStackVersions.stack;
+    const stackVersion = selectedStack.ClusterStackVersions.version;
+    const repoVersionId =
+      selectedStack.repository_versions[0].RepositoryVersions.id;
+
+    try {
+      // If skip validation is checked, proceed directly to saving
+      if (skipRepoValidation) {
+        await saveRepositories(stack, stackVersion, repoVersionId.toString());
+        return;
+      }
+
+      // Validate each repository
+      const operatingSystems =
+        selectedStack.repository_versions[0].operating_systems;
+      const validationPromises = [];
+
+      for (const os of operatingSystems) {
+        const osType = os.OperatingSystems.os_type;
+
+        for (const repo of os.repositories) {
+          const repoId = repo.Repositories.repo_id;
+          const repoName = repo.Repositories.repo_name;
+          const baseUrl = repoUrls[repoId] || repo.Repositories.base_url;
+
+          validationPromises.push(
+            VersionsApi.validateRepos(stack, stackVersion, osType, repoId, {
+              base_url: baseUrl,
+              repo_name: repoName,
+            }).catch((err) => {
+              // If validation fails, throw an error with details
+              const errorMessage =
+                err instanceof Error ? err.message : String(err);
+              throw new Error(
+                `Failed to validate repository ${repoName}: ${errorMessage}`
+              );
+            })
+          );
+        }
+      }
+
+      // Wait for all validations to complete
+      await Promise.all(validationPromises);
+
+      // If all validations pass, save the repositories
+      await saveRepositories(stack, stackVersion, repoVersionId.toString());
+    } catch (err) {
+      const errorMessage = err instanceof Error ? err.message : String(err);
+      toast.error(`Validation failed: ${errorMessage}`);
+    } finally {
+      setValidatingRepos(false);
+    }
+  }
+  return (
+    <Modal
+      isOpen={isOpen}
+      onClose={onClose}
+      modalTitle="Repositories"
+      modalBody={getRepoModalBody()}
+      options={{
+        cancelableViaBtn: true,
+        okButtonText: validatingRepos ? "VALIDATING..." : "SAVE",
+        modalSize: "modal-lg",
+        okButtonDisabled: validatingRepos,
+      }}
+      successCallback={() => validateAndSaveRepos()}
+    />
+  );
+}
+
+export default RepoModal;
\ No newline at end of file
diff --git a/ambari-web/latest/src/components/Tooltip.tsx b/ambari-web/latest/src/components/Tooltip.tsx
index 204b704cd0..320cd9f2d7 100644
--- a/ambari-web/latest/src/components/Tooltip.tsx
+++ b/ambari-web/latest/src/components/Tooltip.tsx
@@ -20,7 +20,7 @@ import React from "react";
 import { OverlayTrigger, Popover } from "react-bootstrap";
 
 interface TooltipComponentProps {
-  message: string;
+  message: any;
   children: any;
   heading?: string;
   placement?: "top" | "right" | "bottom" | "left";
diff --git a/ambari-web/latest/src/hooks/useUpgrade.ts b/ambari-web/latest/src/hooks/useUpgrade.ts
index 34d644ba02..b68de2c268 100644
--- a/ambari-web/latest/src/hooks/useUpgrade.ts
+++ b/ambari-web/latest/src/hooks/useUpgrade.ts
@@ -24,6 +24,7 @@ import { StackVersion, UpgradeData, UpgradeGroup, UpgradeItem, UpgradeParameters
 import { get, merge, set } from "lodash";
 import { failedStatuses, activeStatuses, getUpgradeRequestStatus } from "../Utils/Utility";
 import { AppContext } from "../store/context";
+import ClusterApi from "../api/clusterApi";
 
 export function useUpgrade(upgradeId: number, onlyView: boolean) {
   const [data, setData] = useState<UpgradeData | null>(null);
@@ -60,9 +61,12 @@ export function useUpgrade(upgradeId: number, onlyView: boolean) {
     upgradeRunning: false,
     showPauseButton: false,
     upgradeStatusLabel: "",
-    upgradeAssociatedversion: ""
+    upgradeAssociatedversion: "",
+    slaveComponentFailures: false,
+    serviceCheckFailures: false,
+    upgradeMethod: "",
   });
-  const { clusterName, setUpgradeState, setCurrentStackVersion } = useContext(AppContext);
+  const { clusterName, setUpgradeState, setCurrentStackVersion, setUpgradeIsFinalizeItem } = useContext(AppContext);
 
   const { pausePolling } = usePolling(fetchOperations, 6000);
   let slaveComponentStructuredInfo: any;
@@ -187,6 +191,17 @@ export function useUpgrade(upgradeId: number, onlyView: boolean) {
       if(isServiceCheckFailuresItem && manualItem)
         areServiceCheckFailuresServicenamesLoaded = await getServiceCheckItem(manualItem)
 
+      const serviceCheckFailures = get(data, "Upgrade.skip_service_check_failures", false);
+      const slaveComponentFailures = get(data, "Upgrade.skip_failures", false);
+      const upgradeMethod = get(data, "Upgrade.upgrade_type", "");
+
+      setUpgradeIsFinalizeItem(isFinalizeItem);
+      await ClusterApi.postPersistData(
+        JSON.stringify({
+          upgradeIsFinalizeItem: JSON.stringify(isFinalizeItem)
+        })
+      )
+
       setUpgradeParameters({
         isDowngrade: isDowngrade,
         isDowngradeAvailable: isDowngradeAvailable,
@@ -217,7 +232,10 @@ export function useUpgrade(upgradeId: number, onlyView: boolean) {
         upgradeRunning: upgradeRunning,
         showPauseButton: showPauseButton,
         upgradeStatusLabel: upgradeStatusLabel || "",
-        upgradeAssociatedversion: upgradeAssociatedversion
+        upgradeAssociatedversion: upgradeAssociatedversion,
+        slaveComponentFailures: slaveComponentFailures,
+        serviceCheckFailures: serviceCheckFailures,
+        upgradeMethod: upgradeMethod,
       });
     }
     fetchData();
@@ -315,9 +333,40 @@ export function useUpgrade(upgradeId: number, onlyView: boolean) {
     });
   };
 
-  const handleCopy = (text: string) => {
-    navigator.clipboard.writeText(text);
-    alert("Copied to clipboard");
+  const handleCopy = async (text: string) => {
+    try {
+      // Check if clipboard API is available (HTTPS required)
+      if (navigator.clipboard && window.isSecureContext) {
+        await navigator.clipboard.writeText(text);
+        alert("Copied to clipboard");
+        return;
+      }
+      
+      // Fallback for HTTP or older browsers
+      const textArea = document.createElement('textarea');
+      textArea.value = text;
+      textArea.style.position = 'fixed';
+      textArea.style.left = '-999999px';
+      textArea.style.top = '-999999px';
+      document.body.appendChild(textArea);
+      textArea.focus();
+      textArea.select();
+      
+      try {
+        document.execCommand('copy');
+        alert("Copied to clipboard");
+      } catch (fallbackErr) {
+        console.error("Fallback copy failed: ", fallbackErr);
+        // Show user a message to manually copy
+        alert(`Please copy this manually: ${text}`);
+      }
+      
+      document.body.removeChild(textArea);
+    } catch (err) {
+      console.error('Failed to copy:', err);
+      // Final fallback - show text for manual copy
+      alert(`Please copy this manually: ${text}`);
+    }
   };
 
   const handleOpenInNewTab = (content: string) => {
@@ -357,10 +406,16 @@ export function useUpgrade(upgradeId: number, onlyView: boolean) {
     }
   }
 
-  function finish() {
+  async function finish() {
     const upgradeVersion = get(data, "Upgrade.associated_version", "");
     setCurrentStackVersion(upgradeVersion);
     setUpgradeState("NOT_REQUIRED");
+    setUpgradeIsFinalizeItem(false);
+    await ClusterApi.postPersistData(
+      JSON.stringify({
+        upgradeIsFinalizeItem: JSON.stringify(false)
+      })
+    )
     window.location.reload();
   }
 
diff --git a/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/ListVersion.tsx b/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/ListVersion.tsx
index b52bf421cb..080b4e73bb 100644
--- a/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/ListVersion.tsx
+++ b/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/ListVersion.tsx
@@ -4,203 +4,140 @@
  * distributed with this work for additional information
  * regarding copyright ownership.  The ASF licenses this file
  * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
+ * 'License'); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
+ * distributed under the License is distributed on an 'AS IS' BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-import { JSX, useContext, useEffect, useRef, useState } from "react";
+import {useContext, useEffect, useRef, useState, useCallback } from "react";
 import {
+  Badge,
   Button,
   ButtonGroup,
+  Col,
   Dropdown,
   Form,
-  OverlayTrigger,
-  Tooltip,
+  Row,
 } from "react-bootstrap";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import {
-  faBolt,
-  faDashboard,
   faEdit,
   faExternalLink,
+  faDashboard,
+  faBolt,
   faTimes,
   faWarning,
   IconDefinition,
+  faExclamationTriangle,
+  faBug,
+  faQuestionCircle
 } from "@fortawesome/free-solid-svg-icons";
+import { cloneDeep, get, set } from "lodash";
+import { Link, useNavigate } from "react-router-dom";
+import { StackVersion, Item, Response, ClusterCheckPopupData } from "./types";
 import VersionsApi from "../../../api/VersionsApi";
 import toast from "react-hot-toast";
 import Spinner from "../../../components/Spinner";
-import Table from "../../../components/Table";
-import { cloneDeep, get, set } from "lodash";
-import Select from "react-select";
 import Modal from "../../../components/Modal";
 import usePolling from "../../../hooks/usePolling";
-import { Link } from "react-router-dom";
+import Tooltip from "../../../components/Tooltip";
+import Select from "react-select";
 import { AppContext } from "../../../store/context";
-import { RequestApi } from "../../../api/requestApi";
-import OperationsProgress from "../../../components/OperationProgress";
-import { ClusterCheckPopupData, Item, Response, StackVersion } from "./types";
-import { translate, translateWithVariables } from "../../../Utils/Utility";
 import modalManager from "../../../store/ModalManager";
+import Table from "../../../components/Table";
+import { initialOptions, initialUpgradeMethods, showAlertModal, translate, getUpgradeRequestStatus, translateWithVariables } from "../../../Utils/Utility";
 import ClusterApi from "../../../api/clusterApi";
+import OperationsProgress from "../../../components/OperationProgress";
 import Upgrade from "./Upgrade";
+import { RequestApi } from "../../../api/requestApi";
+import RepoModal from "../../../components/RepoModal";
 
-const initialOptions = [
-  { key: "ALL", values: ["ALL"], count: 0 },
-  {
-    key: "NOT INSTALLED",
-    values: ["INSTALL_FAILED", "INSTALLING", "NOT_REQUIRED"],
-    count: 0,
-  },
-  { key: "UPGRADE READY", values: ["UPGRADE_READY"], count: 0 },
-  { key: "CURRENT", values: ["CURRENT"], count: 0 },
-  { key: "INSTALLED", values: ["INSTALLED"], count: 0 },
-  {
-    key: "UPGRADE/DOWNGRADE IN PROGRESS",
-    values: ["Upgrade/Downgrade in Progress"],
-    count: 0,
-  },
-  { key: "READY TO FINALIZE", values: ["Ready to Finalize"], count: 0 },
-];
-
-const initialUpgradeMethods = [
-  {
-    displayName: translate(
-      "admin.stackVersions.version.upgrade.upgradeOptions.RU.title"
-    ),
-    type: "ROLLING",
-    icon: "faDashboard",
-    description: translate(
-      "admin.stackVersions.version.upgrade.upgradeOptions.RU.description"
-    ),
-    selected: false,
-    allowed: true,
-    isCheckComplete: false,
-    isCheckRequestInProgress: false,
-    precheckResultsMessage: "",
-    preCheckResultsModalContent: null as JSX.Element | null,
-    precheckResultsTitle: "",
-    action: "",
-    isWizardRestricted: false,
-  },
-  {
-    displayName: translate(
-      "admin.stackVersions.version.upgrade.upgradeOptions.EU.title"
-    ),
-    type: "NON_ROLLING",
-    icon: "faBolt",
-    description: translate(
-      "admin.stackVersions.version.upgrade.upgradeOptions.EU.description"
-    ),
-    selected: false,
-    allowed: true,
-    isCheckComplete: false,
-    isCheckRequestInProgress: false,
-    precheckResultsMessage: "",
-    preCheckResultsModalContent: null as JSX.Element | null,
-    precheckResultsTitle: "",
-    action: "",
-    isWizardRestricted: false,
-  },
-  {
-    displayName: translate(
-      "admin.stackVersions.version.upgrade.upgradeOptions.HOU.title"
-    ),
-    type: "HOST_ORDERED",
-    icon: "faBolt",
-    description: "",
-    selected: false,
-    allowed: false,
-    isCheckComplete: false,
-    isCheckRequestInProgress: false,
-    precheckResultsMessage: "",
-    preCheckResultsModalContent: null as JSX.Element | null,
-    precheckResultsTitle: "",
-    action: "",
-    cantBeStarted: true,
-  },
-];
-
-const iconMapping: { [key: string]: IconDefinition } = {
+export const iconMapping: { [key: string]: IconDefinition } = {
   faDashboard: faDashboard,
   faBolt: faBolt,
 };
 
 export default function Versions() {
-  const [loading, setLoading] = useState(false);
   const [options, setOptions] = useState(initialOptions);
   const [selectedOption, setSelectedOption] = useState(options[0]);
+  const [loading, setLoading] = useState(false);
   const [services, setServices] = useState<string[]>([]);
   const [originalStacks, setOriginalStacks] = useState<StackVersion[]>([]);
   const [stacks, setStacks] = useState<StackVersion[]>([]);
+  const [stackVersionError, setStackVersionError] = useState<any>(null);
   const [upgradeMethods, setUpgradeMethods] = useState(initialUpgradeMethods);
   const [methodType, setMethodType] = useState("");
+  const [, setCompletionStatus] = useState(false);
+  const [selectedStack, setSelectedStack] = useState<StackVersion>();
+  const selectedStackRef = useRef<StackVersion>(selectedStack);
   const [currentUpgradeTypes, setCurrentUpgradeTypes] = useState<string[]>([]);
-  const { clusterName, setUpgradeId, upgradeState, setUpgradeVersionDisplayName } = useContext(AppContext);
+  const [isOperationInProgress, setIsOperationInProgress] = useState(false);
+  const [operationsState, setOperationsState] = useState<any[]>([]);
+  const [slaveComponentFailures, setSlaveComponentFailures] = useState(false);
+  const [serviceCheckFailures, setServiceCheckFailures] = useState(false);
+  const [isRestoring, setIsRestoring] = useState(true);
+  const { clusterName, setUpgradeId, upgradeState, setIsPatchUpgrade, setUpgradeVersionDisplayName, allHostNames, upgradeVersionDisplayName, upgradeId, upgradeDirection } = useContext(AppContext);
+  
+  const packagesPayloadRef = useRef<any>({});
   
   const [versionModal, setVersionModal] = useState(false);
   const [installPackagesModal, setInstallPackagesModal] = useState(false);
-  const [manageVersionModal, setManageVersionsModal] = useState(false);
-  const [repoModal, setRepoModal] = useState(false);
   const [hostModal, setHostModal] = useState(false);
   const [upgradeModal, setUpgradeModal] = useState(false);
   const [upgradeCheckModal, setUpgradeCheckModal] = useState(false);
   const [upgradeConfirmationModal, setUpgradeConfirmationModal] = useState(false);
-  const [, setCompletionStatus] = useState(false);
-  const [selectedStack, setSelectedStack] = useState<StackVersion>();
-  const selectedStackRef = useRef<StackVersion>(selectedStack);
-  const [operations, setOperations] = useState({});
-  const [payload, setPayload] = useState({});
+  const [manageVersionModal, setManageVersionsModal] = useState(false);
+  const [alertModal, setAlertModal] = useState(false);
 
   const hostModalContent = useRef("");
   const hostModalTitle = useRef("");
-  const upgradeModalContent = useRef<JSX.Element | null>(null);
+  const hostModalData = useRef<any>({
+    versionStatus: "",
+    versionName: "",
+  });
+  // Remove the ref since we'll render content directly
   const upgradeMethodsRef = useRef(initialUpgradeMethods);
-  const upgradeOkButton = useRef<Boolean>(true);
+  const [isProceedButtonDisabled, setIsProceedButtonDisabled] = useState(true);
   const showRerunButton = useRef<Boolean>(true);
   const showUpgradeProceedButton = useRef<boolean>(true);
+  
+  // Cache for pre-upgrade check results to avoid redundant API calls
+  const preCheckCacheRef = useRef<Map<string, any>>(new Map());
+  
+  // Refs for fast switching between upgrade methods
+  const methodTypeRef = useRef("");
+
+  const navigate = useNavigate();
 
   const {} = usePolling(fetchServices, 6000);
 
-  useEffect(() => {
-    if (selectedOption.key !== "ALL") {
-      setStacks(
-        originalStacks.filter((stack) => {
-          return selectedOption.values.includes(
-            stack.ClusterStackVersions.state
-          );
-        })
-      );
-    } else {
-      setStacks(originalStacks);
+  const handleSelectChange = (selected: any) => {
+    const option = options.find((o) => o.key === selected.value);
+    if (option) {
+      setSelectedOption(option);
     }
+  };
 
-    const updatedOptions = options.map((option) => {
-      let count;
-      if (option.key === "ALL") {
-        count = originalStacks.length;
-      } else {
-        count = originalStacks.reduce((acc, stack) => {
-          if (option.values.includes(stack.ClusterStackVersions.state)) {
-            return acc + 1;
-          }
-          return acc;
-        }, 0);
-      }
-
-      return { ...option, count };
-    });
-
-    setOptions(updatedOptions);
-  }, [originalStacks, selectedOption]);
+  // Optimized method type selection handler using useCallback
+  const handleMethodTypeSelection = useCallback((newMethodType: string) => {
+    methodTypeRef.current = newMethodType;
+    setMethodType(newMethodType);
+    
+    // Fast button state update using ref
+    const selectedMethod = upgradeMethodsRef.current.find(method => method.type === newMethodType);
+    if (selectedMethod) {
+      const hasRequiredFailures = selectedMethod.precheckResultsMessage.includes("Required");
+      const isStillLoading = selectedMethod.isCheckRequestInProgress;
+      setIsProceedButtonDisabled(hasRequiredFailures && !isStillLoading);
+    }
+  }, []);
 
   async function fetchServices() {
     try {
@@ -224,7 +161,7 @@ export default function Versions() {
         });
         setOriginalStacks(filteredStacks);
       } else {
-        setOriginalStacks(stacks);
+        setOriginalStacks(stacks)
       }
 
       const services = Object.keys(
@@ -240,8 +177,86 @@ export default function Versions() {
 
   useEffect(() => {
     fetchServices();
+    restoreOperationsState();
   }, []);
 
+  async function restoreOperationsState() {
+    try {
+      setIsRestoring(true);
+      const savedData = await ClusterApi.getPersistData("versionOperations");
+      if (savedData) {
+        let savedOperationsState;
+        if (typeof savedData === 'string') {
+          savedOperationsState = JSON.parse(savedData);
+        } else {
+          savedOperationsState = savedData;
+        }
+        if (savedOperationsState && Array.isArray(savedOperationsState) && savedOperationsState.length > 0) {
+          setOperationsState(savedOperationsState);
+          
+          const hasActiveOperations = savedOperationsState.some((op: any) => 
+            op.status === 'IN_PROGRESS' || op.status === 'PENDING'
+          );
+          if (hasActiveOperations) {
+            setIsOperationInProgress(true);
+          }
+        }
+      }
+    } catch (error) {
+      console.error("Failed to restore operations state:", error);
+    } finally {
+      setIsRestoring(false);
+    }
+  }
+
+  useEffect(() => {
+    if (selectedOption.key !== "ALL") {
+      setStacks(
+        originalStacks.filter((stack) => {
+          return selectedOption.values.includes(
+            stack.ClusterStackVersions.state
+          );
+        })
+      );
+    } else {
+      setStacks(originalStacks);
+    }
+
+    const updatedOptions = options.map((option) => {
+      let count;
+      if (option.key === "ALL") {
+        count = originalStacks.length;
+      } else {
+        count = originalStacks.reduce((acc, stack) => {
+          if (option.values.includes(stack.ClusterStackVersions.state)) {
+            return acc + 1;
+          }
+          return acc;
+        }, 0);
+      }
+
+      return { ...option, count };
+    });
+
+    setOptions(updatedOptions);
+  }, [originalStacks, selectedOption]);
+
+  useEffect(() => {
+    const errorStack = originalStacks
+      .filter(stack => stack.ClusterStackVersions.state === 'OUT_OF_SYNC')
+      .find(stack => stack.repository_versions[0].RepositoryVersions.type === 'STANDARD');
+    
+    if (errorStack) {
+      setStackVersionError({
+        title: translate('admin.stackVersions.version.errors.outOfSync.title'),
+        description: translate('admin.stackVersions.version.errors.outOfSync.desc'),
+        stackFullName: errorStack.repository_versions[0].RepositoryVersions.stack_name + '-' + errorStack.repository_versions[0].RepositoryVersions.repository_version
+      });
+    } else {
+      setStackVersionError(null);
+    }
+  }, [originalStacks]);
+
   useEffect(() => {
     selectedStackRef.current = selectedStack;
     // update the stacks with selectedStack
@@ -261,149 +276,107 @@ export default function Versions() {
 
   useEffect(() => {
     upgradeMethodsRef.current = upgradeMethods;
+  }, [upgradeMethods]);
 
-    // Update the upgrade modal content when upgrade methods change
-    if (upgradeModal && selectedStackRef.current) {
-      const modalContent = (
-        <div className="upgrade-modal">
-          <div>
-            You are about to perform an upgrade to{" "}
-            <strong>
-              {selectedStackRef.current?.repository_versions[0]?.RepositoryVersions
-                ?.display_name || "Unknown"}
-            </strong>
-          </div>
-          <div className="pt-1">Choose the upgrade method:</div>
-
-          <div className="upgrade-options-container">
-            {upgradeMethods
-              .filter(
-                (method) =>
-                  method.allowed && currentUpgradeTypes.includes(method.type)
-              )
-              .map((method) => (
-                <div
-                  key={method.type}
-                  className={`upgrade-method ${
-                    methodType === method.type ? "selected" : ""
-                  }`}
-                  onClick={() => {
-                    setMethodType(method.type);
-                    if (method.precheckResultsMessage.includes("Required")) {
-                      upgradeOkButton.current = true;
-                    } else {
-                      upgradeOkButton.current = false;
-                    }
-                  }}
-                >
-                  <FontAwesomeIcon
-                    className="upgrade-method-icon"
-                    icon={iconMapping[method.icon]}
-                  />
-                  <div className="upgrade-method-title">
-                    {method.displayName}
-                  </div>
-                  <div className="upgrade-method-description">
-                    {method.description}
-                  </div>
-                  <div
-                    className="upgrade-method-checks"
-                    onClick={(e) => {
-                      e.stopPropagation();
-                      showRerunButton.current = true;
-                      setUpgradeCheckModal(true);
-                      setMethodType(method.type);
-                    }}
-                  >
-                    {method.precheckResultsMessage.includes("Required") ? (
-                      <FontAwesomeIcon
-                        className="text-danger mx-1"
-                        icon={faTimes}
-                      />
-                    ) : (
-                      <FontAwesomeIcon
-                        className="text-warning mx-1"
-                        icon={faWarning}
-                      />
-                    )}
-                    Checks: {method.precheckResultsMessage}
-                  </div>
-                </div>
-              ))}
-          </div>
-
-          <div className="upgrade-failure-tolerance">
-            <div>Select optional upgrade failure tolerance:</div>
-            <Form className="pt-2">
-              <Form.Group controlId="serviceCheck">
-                <Form.Check
-                  type="checkbox"
-                  label="Skip all Service Check failures"
-                />
-              </Form.Group>
-              <Form.Group controlId="slaveComponentFailures">
-                <Form.Check
-                  type="checkbox"
-                  label="Skip all Slave Component failures"
-                />
-              </Form.Group>
-            </Form>
-          </div>
-
-          <div className="upgrade-warning">
-            Cluster alerts will still be visible and recorded in Ambari but
-            notifications (such as Email and SNMP) will be suppressed during the
-            upgrade.
-          </div>
-        </div>
-      );
-      upgradeModalContent.current = modalContent;
+  useEffect(() => {
+    if (methodType && upgradeMethods.length > 0) {
+      const selectedMethod = upgradeMethods.find(method => method.type === methodType);
+      if (selectedMethod) {
+        // Enable proceed button if method has no required failures or is still loading
+        const hasRequiredFailures = selectedMethod.precheckResultsMessage.includes("Required");
+        const isStillLoading = selectedMethod.isCheckRequestInProgress;
+        
+        // Enable button if not loading and no required failures, or if no method is selected yet
+        setIsProceedButtonDisabled(hasRequiredFailures && !isStillLoading);
+      } else {
+        // No method selected, disable button
+        setIsProceedButtonDisabled(true);
+      }
+    } else {
+      // No method type selected, disable button
+      setIsProceedButtonDisabled(true);
     }
-  }, [upgradeMethods, upgradeModal, methodType]);
+  }, [methodType, upgradeMethods]);
 
   if (loading) {
     return <Spinner />;
   }
 
-  const columns = [
-    {
-      accessorKey: "name",
-      header: "",
-      cell: (info: any) => info.row.original,
-      width: "10%",
-    },
-    ...stacks.map((stackData: StackVersion, index: number) => {
-      return {
-        accessorKey: `stack-${index}`,
-        header: getStackHeader(stackData),
-        cell: (info: any) => {
-          const service = get(
-            stackData.ClusterStackVersions.repository_summary.services,
-            info.row.original,
-            { version: "UNKNOWN" }
+  function renderOperationProgress() {
+    return (
+      <OperationsProgress
+        operations={ operationsState as any }
+        title="install packages"
+        description="install packages"
+        setCompletionStatus={ async () => {
+          setCompletionStatus(true);
+          setIsOperationInProgress(false);
+          setOperationsState([]);
+          
+          const selectedStackCopy = cloneDeep(selectedStack);
+          if (selectedStackCopy) {
+            set(selectedStackCopy, "ClusterStackVersions.state", "INSTALLED");
+            setSelectedStack(selectedStackCopy);
+            selectedStackRef.current = selectedStackCopy;
+          }
+          
+          // Reset operations state to empty array
+          await ClusterApi.postPersistData(
+            JSON.stringify({
+              versionOperations: JSON.stringify([]),
+            })
           );
-          return service.version;
-        },
-        id: `stack-${index}`,
-      };
-    }),
-  ];
-
-  const handleSelectChange = (selected: any) => {
-    const option = options.find((o) => o.key === selected.value);
-    if (option) {
-      setSelectedOption(option);
-    }
-  };
+        }}
+        errorCallback={async (errorMsg) => {
+          setIsOperationInProgress(false);
+          setOperationsState([]);
+          
+          const selectedStackCopy = cloneDeep(selectedStack);
+          if (selectedStackCopy) {
+            set(
+              selectedStackCopy,
+              "ClusterStackVersions.state",
+              "INSTALL_FAILED"
+            );
+            setSelectedStack(selectedStackCopy);
+            selectedStackRef.current = selectedStackCopy;
+          }
+          
+          // Reset operations state to empty array
+          await ClusterApi.postPersistData(
+            JSON.stringify({
+              versionOperations: JSON.stringify([]),
+            })
+          );
+          
+          if (!alertModal) {
+            setAlertModal(true);
+            showAlertModal("Packages could not be installed", errorMsg);
+          }
+        }}
+        dispatch={async (operationsState: any) => {
+          setIsOperationInProgress(true);
+          setOperationsState(operationsState);
+          
+          // Persist the current operations state
+          await ClusterApi.postPersistData(
+            JSON.stringify({
+              versionOperations: JSON.stringify(operationsState),
+            })
+          );
+        }}
+      />
+    );
+  }
 
   function getStackHeader(stackData: StackVersion) {
     return (
-      <div>
-        <div>
+      <div className={`p-2`}>
+        <p className="text-center fs-16 fw-500">
           {stackData.repository_versions[0].RepositoryVersions.display_name}
-        </div>
-        <div className="mt-2">
-          <small className="text-muted mt-2">
+        </p>
+        <div className="mt-2 text-center">
+          <small className="text-muted">
             (
             {
               stackData.repository_versions[0].RepositoryVersions
@@ -412,78 +385,136 @@ export default function Versions() {
             )
           </small>
         </div>
-        <div className="mt-2">
-          <small
-            className="custom-link"
-            onClick={() => {
+        {stackData.repository_versions[0].RepositoryVersions.type === "PATCH" ? (
+          <div className="text-center mt-2 fs-6 text-warning">
+              <FontAwesomeIcon className="me-2" icon={faBug}/>
+              Patch
+          </div>
+        ) : (
+          <div className="mt-2 fs-6">&nbsp;</div>
+        )}
+        <div className="mt-2 mb-2 text-center">
+          <a
+            href="#"
+            className="text-primary"
+            onClick={(e) => {
+              e.preventDefault();
               setSelectedStack(stackData);
               selectedStackRef.current = stackData;
               setVersionModal(true);
             }}
           >
             Show Details
-          </small>
+          </a>
         </div>
-        {getButtonName(stackData) === "installing" ||
-        getButtonName(stackData) === "intermediateInstalling" ? (
-          <Link to={""}>
-            <OperationsProgress
-              operations={operations as any}
-              title="install packages"
-              description="install packages"
-              setCompletionStatus={setCompletionStatus}
-            />
-          </Link>
-        ) : getButtonName(stackData) === "UPGRADE" ? (
-          <Dropdown as={ButtonGroup}>
+        <div className="text-center">
+          {getButtonName(stackData) === "installing" ||
+          getButtonName(stackData) === "intermediateInstalling" ? (
+            isRestoring ? (
+              <Spinner />
+            ) :(
+              <Link to={""}>
+                {renderOperationProgress()}
+              </Link>
+            )
+          ) : getButtonName(stackData) === "upgradeInProgress" ? (
             <Button
-              variant="success"
-              className="text-uppercase"
+              variant="light"
               size="sm"
-              disabled={upgradeState !== "NOT_REQUIRED" &&
-                  upgradeState !== "COMPLETED"}
-              onClick={() => handleUpgradeButton(stackData)}
+              className="custom-link color-white"
+              onClick={() => {
+                setSelectedStack(stackData);
+                selectedStackRef.current = stackData;
+                modalManager.show(<Upgrade upgradeId={upgradeId} />);
+              }}
             >
-              Upgrade
+              {translate(getUpgradeStatus(stackData).statusText || "admin.stackUpgrade.state.inProgress")}
             </Button>
-            <Dropdown.Toggle split variant="success" id="dropdown" />
-            <Dropdown.Menu>
-              <Dropdown.Item
-              disabled={upgradeState !== "NOT_REQUIRED" &&
-                  upgradeState !== "COMPLETED"}
-                onClick={() => installPackagesPayloadSet(stackData)}
+          ) : getButtonName(stackData) === "current" ? (
+            <Dropdown as={ButtonGroup} className="upgrade-dropdown">
+              <Button
+                variant="success"
+                className="text-uppercase"
+                disabled
+                size="sm"
               >
-                Re-install
-              </Dropdown.Item>
-              <Dropdown.Item
-                onClick={() => {
-                  showUpgradeProceedButton.current = false;
-                  if (selectedStackRef.current) {
-                    handleUpgradeClick(selectedStackRef.current);
-                  } else {
-                    toast.error("No stack selected for upgrade.");
-                  }
-                }}
+                CURRENT
+              </Button>
+            </Dropdown>
+
+          ) : getButtonName(stackData) === "upgrade" ? (
+            <Dropdown as={ButtonGroup} className="upgrade-dropdown">
+              <Button
+                variant="success"
+                className="text-uppercase"
+                size="sm"
+                disabled={(upgradeState !== "NOT_REQUIRED" &&
+                  upgradeState !== "COMPLETED")}
+                onClick={() => handleUpgradeButton(stackData)}
               >
-                Pre-upgrade check
-              </Dropdown.Item>
-            </Dropdown.Menu>
-          </Dropdown>
-        ) : (
-          <Button
-            className="mt-2"
-            variant="success"
-            size="sm"
-            onClick={() => handleUpgradeButton(stackData)}
-          >
-            {getButtonName(stackData)}
-          </Button>
-        )}
+                Upgrade
+              </Button>
+              <Dropdown.Toggle
+                size="sm"
+                split
+                variant="success"
+                id="dropdown"
+              />
+              <Dropdown.Menu className="dropdown-menu-right">
+                <Dropdown.Item
+                disabled={upgradeState !== "NOT_REQUIRED" &&
+                  upgradeState !== "COMPLETED"}
+                  onClick={() => installPackagesPayloadSet(stackData)}
+                >
+                  Re-install
+                </Dropdown.Item>
+                <Dropdown.Item
+                  disabled= {upgradeState !== "NOT_REQUIRED" &&
+                  upgradeState !== "COMPLETED"}
+                  onClick={() => {
+                    showUpgradeProceedButton.current = false;
+                    selectedStackRef.current = stackData;
+                    setSelectedStack(stackData);
+                    if (selectedStackRef.current) {
+                      handleUpgradeClick(selectedStackRef.current);
+                    } else {
+                      toast.error("No stack selected for upgrade.");
+                    }
+                  }}
+                >
+                  Pre-upgrade check
+                </Dropdown.Item>
+              </Dropdown.Menu>
+            </Dropdown>
+          ) : (
+            <Button
+              variant="success"
+              size="sm"
+              className="text-uppercase fw-bold"
+              onClick={() => handleUpgradeButton(stackData)}
+            >
+              {getButtonName(stackData) === "re-install"
+                ? "RE-INSTALL"
+                : getButtonName(stackData).toUpperCase()}
+            </Button>
+          )}
+        </div>
       </div>
     );
   }
 
-  function installPackagesPayloadSet(stackData: StackVersion) {
+  async function installPackagesPayloadSet(stackData: StackVersion) {
+    
+    setOperationsState([]);
+    setIsOperationInProgress(false);
+    
+    // Clear persistent storage
+    await ClusterApi.postPersistData(
+      JSON.stringify({
+        versionOperations: JSON.stringify([]),
+      })
+    );
+    
     setSelectedStack(stackData);
     selectedStackRef.current = stackData;
     const payload = {
@@ -496,7 +527,7 @@ export default function Versions() {
       },
     };
 
-    setPayload(payload);
+    packagesPayloadRef.current = payload;
     setInstallPackagesModal(true);
   }
 
@@ -504,9 +535,10 @@ export default function Versions() {
     setSelectedStack(stackData);
     selectedStackRef.current = stackData;
     switch (getButtonName(stackData)) {
-      case "CURRENT":
+      case "current":
         return;
-      case "UPGRADE":
+      case "upgrade":
+        showUpgradeProceedButton.current = true;
         handleUpgradeClick(stackData);
         return;
       default:
@@ -514,224 +546,14 @@ export default function Versions() {
     }
   }
 
-  function installPackages() {
-    const operations = [
-      {
-        id: "1",
-        label: "installing",
-        skippable: false,
-        context: "install packages",
-        callback: async () => {
-          const reqData = await RequestApi.installPackages(
-            clusterName,
-            payload
-          );
-          return reqData;
-        },
-      },
-    ];
-    setOperations(operations);
-    let selectedStackCopy = cloneDeep(selectedStack);
-    if (selectedStackCopy) {
-      set(selectedStackCopy, "ClusterStackVersions.state", "INTERMEDIATE");
-      setSelectedStack(selectedStackCopy);
-      selectedStackRef.current = selectedStackCopy;
-    }
-    setInstallPackagesModal(false);
-  }
-
-  function getButtonName(stackData: StackVersion) {
-    const stackState = stackData.ClusterStackVersions.state;
-
-    switch (stackState) {
-      case "CURRENT":
-        return "CURRENT";
-      case "INSTALL_FAILED":
-        return "RE-INSTALL";
-      case "INSTALLED":
-        return "UPGRADE";
-      case "INSTALLING":
-        return "installing";
-      case "INTERMEDIATE":
-        return "intermediateInstalling";
-      default:
-        return "INSTALL_PACKAGES";
-    }
-  }
-
-  function getInstallPackageModalBody() {
-    const displayName =
-      selectedStackRef.current?.repository_versions?.[0]?.RepositoryVersions
-        ?.display_name || "N/A";
-    return (
-      <div>
-        You are about to install packages for version
-        <strong>{displayName}</strong> on all hosts.
-      </div>
-    );
-  }
-
-  function getVersionModalBody() {
-    if (!selectedStackRef.current || Object.keys(selectedStackRef.current).length === 0) {
-      return null;
-    }
-
-    const hostStates = selectedStackRef.current.ClusterStackVersions.host_states;
-    const installed = hostStates.INSTALLED.length;
-    const current = hostStates.CURRENT.length;
-    const notInstalled =
-      Object.values(hostStates).flat().length - installed - current;
-
-    return (
-      <div>
-        <div className="d-flex justify-content-center">
-          <div className="fw-bold">
-            {selectedStackRef.current?.repository_versions[0]?.RepositoryVersions
-              ?.display_name || "NA"}
-          </div>
-          <small className="mx-2">
-            <OverlayTrigger
-              placement="top"
-              delay={{ show: 250, hide: 400 }}
-              overlay={<Tooltip>Click to Edit Repositories</Tooltip>}
-            >
-              <FontAwesomeIcon
-                onClick={() => setRepoModal(true)}
-                icon={faEdit}
-              />
-            </OverlayTrigger>
-          </small>
-        </div>
-        <div className="mt-2 text-center">
-          <small className="text-muted mt-2">
-            (
-            {selectedStackRef.current?.repository_versions?.[0]?.RepositoryVersions
-              ?.repository_version || "NA"}
-            )
-          </small>
-        </div>
-        <div className="text-center">
-          {getButtonName(selectedStackRef.current) === "installing" ||
-          getButtonName(selectedStackRef.current) === "intermediateInstalling" ? (
-            <Link to={""}>
-              <OperationsProgress
-                operations={operations as any}
-                title="install packages"
-                description="install packages"
-                setCompletionStatus={setCompletionStatus}
-              />
-            </Link>
-          ) : getButtonName(selectedStackRef.current) === "UPGRADE" ? (
-            <Dropdown as={ButtonGroup}>
-              <Button variant="success">Upgrade</Button>
-              <Dropdown.Toggle split variant="success" id="dropdown" />
-              <Dropdown.Menu>
-                <Dropdown.Item
-                  onClick={() => {
-                    if(selectedStackRef.current)
-                      installPackagesPayloadSet(selectedStackRef.current)
-                    }}
-                >
-                  Re-install
-                </Dropdown.Item>
-                <Dropdown.Item>Pre-upgrade check</Dropdown.Item>
-              </Dropdown.Menu>
-            </Dropdown>
-          ) : (
-            <Button
-              className="mt-2"
-              variant="success"
-              size="sm"
-              onClick={() => {
-                if(selectedStackRef.current)
-                handleUpgradeButton(selectedStackRef.current)
-              }}
-            >
-              {getButtonName(selectedStackRef.current)}
-            </Button>
-          )}
-        </div>
-        <div>
-          <div className="text-center mt-3">Hosts</div>
-          <div className="d-flex justify-content-between mt-2">
-            <div>
-              <Button
-                variant="link"
-                onClick={() =>
-                  handleHostClick(
-                    "notInstalled",
-                    Object.values(hostStates)
-                      .flat()
-                      .filter(
-                        (host) =>
-                          !hostStates.CURRENT.includes(host) &&
-                          !hostStates.INSTALLED.includes(host)
-                      )
-                  )
-                }
-                disabled={notInstalled === 0}
-              >
-                {notInstalled}
-              </Button>
-              <div>not installed</div>
-            </div>
-            <div>
-              <Button
-                variant="link"
-                onClick={() =>
-                  handleHostClick("installed", hostStates.INSTALLED)
-                }
-                disabled={installed === 0}
-              >
-                {installed}
-              </Button>
-              <div>installed</div>
-            </div>
-            <div>
-              <Button
-                variant="link"
-                onClick={() => handleHostClick("current", hostStates.CURRENT)}
-                disabled={current === 0}
-              >
-                {current}
-              </Button>
-              <div>current</div>
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  }
-
-  function handleHostClick(status: string, hosts: string[]) {
-    const versionStatus =
-      status === "current"
-        ? "Current"
-        : status === "installed"
-        ? "Installed"
-        : "Not installed";
-    const versionName =
-      selectedStackRef.current?.repository_versions[0]?.RepositoryVersions?.display_name ||
-      "N/A";
-    const hostList = hosts.join("\n\n");
-
-    hostModalContent.current = `${versionName} is ${
-      versionStatus.toLowerCase() === "current"
-        ? "applied"
-        : versionStatus.toLowerCase()
-    } on ${hosts.length} hosts:\n\n\n${hostList}`;
-    hostModalTitle.current = `Version Status: ${versionStatus}`;
-    setHostModal(true);
-  }
-
-  async function handleUpgradeClick(stack: StackVersion) {
-    const response = await VersionsApi.get_supported_upgradeTypes(
-      stack.ClusterStackVersions.stack,
-      stack.ClusterStackVersions.version,
-      stack.repository_versions[0].RepositoryVersions.repository_version
-    );
-    const upgradeTypes =
-      response.items[0].CompatibleRepositoryVersions.upgrade_types;
+  async function handleUpgradeClick(stack: StackVersion) {
+    const response = await VersionsApi.get_supported_upgradeTypes(
+      stack.ClusterStackVersions.stack,
+      stack.ClusterStackVersions.version,
+      stack.repository_versions[0].RepositoryVersions.repository_version
+    );
+    const upgradeTypes =
+      response.items[0].CompatibleRepositoryVersions.upgrade_types;
 
     // Store upgrade types in state instead of in the stack object
     setCurrentUpgradeTypes(upgradeTypes);
@@ -745,103 +567,6 @@ export default function Versions() {
     upgradeMethodsRef.current = updateMethods;
     setUpgradeMethods(updateMethods);
 
-    // Initial modal content - will be updated when pre-check results are available
-    const modalContent = (
-      <div className="upgrade-modal">
-        <div>
-          You are about to perform an upgrade to{" "}
-          <strong>
-            {stack.repository_versions[0].RepositoryVersions.display_name}
-          </strong>
-        </div>
-        <div className="pt-1">Choose the upgrade method:</div>
-
-        <div className="upgrade-options-container">
-          {upgradeMethods
-            .filter(
-              (method) => method.allowed && upgradeTypes.includes(method.type)
-            )
-            .map((method) => (
-              <div
-                key={method.type}
-                className={`upgrade-method ${
-                  methodType === method.type ? "selected" : ""
-                }`}
-                onClick={() => {
-                  setMethodType(method.type);
-                  if (method.precheckResultsMessage.includes("Required")) {
-                    upgradeOkButton.current = true;
-                  } else {
-                    upgradeOkButton.current = false;
-                  }
-                }}
-              >
-                <FontAwesomeIcon
-                  className="upgrade-method-icon"
-                  icon={iconMapping[method.icon]}
-                />
-                <div className="upgrade-method-title">{method.displayName}</div>
-                <div className="upgrade-method-description">
-                  {method.description}
-                </div>
-                <div
-                  className="upgrade-method-checks"
-                  onClick={(e) => {
-                    e.stopPropagation();
-                    showRerunButton.current = true;
-                    setUpgradeCheckModal(true);
-                    setMethodType(method.type);
-                  }}
-                >
-                  {method.isCheckRequestInProgress ? (
-                    <span>Loading checks...</span>
-                  ) : (
-                    <>
-                      {method.precheckResultsMessage.includes("Required") ? (
-                        <FontAwesomeIcon
-                          className="text-danger mx-1"
-                          icon={faTimes}
-                        />
-                      ) : (
-                        <FontAwesomeIcon
-                          className="text-warning mx-1"
-                          icon={faWarning}
-                        />
-                      )}
-                      Checks: {method.precheckResultsMessage}
-                    </>
-                  )}
-                </div>
-              </div>
-            ))}
-        </div>
-
-        <div className="upgrade-failure-tolerance">
-          <div>Select optional upgrade failure tolerance:</div>
-          <Form className="pt-2">
-            <Form.Group controlId="serviceCheck">
-              <Form.Check
-                type="checkbox"
-                label="Skip all Service Check failures"
-              />
-            </Form.Group>
-            <Form.Group controlId="slaveComponentFailures">
-              <Form.Check
-                type="checkbox"
-                label="Skip all Slave Component failures"
-              />
-            </Form.Group>
-          </Form>
-        </div>
-
-        <div className="upgrade-warning">
-          Cluster alerts will still be visible and recorded in Ambari but
-          notifications (such as Email and SNMP) will be suppressed during the
-          upgrade.
-        </div>
-      </div>
-    );
-    upgradeModalContent.current = modalContent;
     setUpgradeModal(true);
 
     // Run the pre-upgrade checks after setting the initial modal content
@@ -891,13 +616,15 @@ export default function Versions() {
       );
     }
     const header = translateWithVariables("popup.clusterCheck.Upgrade.header", {
-      "0":
-        selectedStackRef.current?.repository_versions[0]?.RepositoryVersions
-          ?.display_name || "Unknown",
+      "0": selectedStackRef.current?.repository_versions[0]?.RepositoryVersions?.display_name || "Unknown"
     });
 
-    const warningTitle = translate("popup.clusterCheck.Upgrade.warning.title");
-    const warningAlert = translate("popup.clusterCheck.Upgrade.warning.alert");
+    const warningTitle = translate(
+      "popup.clusterCheck.Upgrade.warning.title"
+    );
+    const warningAlert = translate(
+      "popup.clusterCheck.Upgrade.warning.alert"
+    );
     const configsMergeWarning = response.items.find(
       (item: Item) => item.UpgradeChecks.id === "CONFIG_MERGE"
     );
@@ -950,7 +677,7 @@ export default function Versions() {
         (config) => config.wasModified === true
       );
 
-    const upgradeCheckModalContent1 = (
+    let upgradeCheckModalContent1 = (
       <>
         {fails.length > 0 && (
           <div>
@@ -989,18 +716,24 @@ export default function Versions() {
         )}
         {configsRecommendations?.length > 0 && (
           <div>
-            <h5>Configuration Recommendations</h5>
-            <ul>
-              {configsRecommendations.map((config, index) => (
-                <li key={index}>
-                  {config.name}: {config.currentValue} (current) vs{" "}
-                  {config.recommendedValue} (recommended)
-                </li>
-              ))}
-            </ul>
-            <p>
-              Review the recommendations before proceeding with the upgrade.
-            </p>
+            <div className="d-flex justify-content-between align-items-center mb-3">
+              <h5 className="mb-0">Recommended Configuration Changes: Manual Review</h5>
+              <Button 
+                variant="link" 
+                size="sm" 
+                className="p-0"
+                onClick={() => openConfigurationInNewTab(configsRecommendations)}
+              >
+                <FontAwesomeIcon icon={faExternalLink} className="me-1" />
+                Open
+              </Button>
+            </div>
+            <div className="alert alert-warning">
+              We've detected the need to update the following properties, but cannot do so automatically 
+              since they have been customized. Please review these properties manually and update the 
+              properties manually where necessary.
+            </div>
+            {renderConfigurationTable(configsRecommendations)}
           </div>
         )}
       </>
@@ -1015,7 +748,9 @@ export default function Versions() {
               : ""
           }`
         : "Passed";
-
+    if(upgradeCheckResult1 === "Passed") {
+      upgradeCheckModalContent1 = <div>{translate("admin.stackVersions.version.upgrade.upgradeOptions.preCheck.allPassed.msg")}</div>
+    }
     // set the content of modal & message in the method.
     const methodIndex = upgradeMethodsRef.current.findIndex(
       (method) => method.type === methodType
@@ -1049,7 +784,7 @@ export default function Versions() {
               <pre className="scrollable-container py-2">
                 <pre className="border-none">Reason: {reason}</pre>
                 <br />
-                <span>Failed on: {failed_on}</span>
+                <span>Failed on: {Array.isArray(failed_on) ? failed_on.join(', ') : failed_on}</span>
               </pre>
             </li>
           </ul>
@@ -1058,20 +793,154 @@ export default function Versions() {
     });
   }
 
-  function getConfigsWarnings(configsMergeWarning: any) {
-    let configs = [];
-    if (
-      configsMergeWarning &&
-      configsMergeWarning.UpgradeChecks?.status === "WARNING"
-    ) {
-      const configsMergeCheckData =
-        configsMergeWarning.UpgradeChecks?.failed_detail;
-      if (configsMergeCheckData && Array.isArray(configsMergeCheckData)) {
-        configs = configsMergeCheckData.reduce((allConfigs, item) => {
-          const isDeprecated = item.new_stack_value == null;
-          const willBeRemoved = item.result_value == null;
+  function openConfigurationInNewTab(configs: any[]) {
+    // Generate HTML content for the configuration table
+    const htmlContent = `
+      <!DOCTYPE html>
+      <html lang="en">
+      <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <title>Recommended Configuration Changes - Manual Review</title>
+        <style>
+          body {
+            font-family: Arial, sans-serif;
+            margin: 20px;
+            background-color: #ffffff;
+          }
+          h1 {
+            color: #333;
+            margin-bottom: 20px;
+          }
+          table {
+            width: 100%;
+            border-collapse: collapse;
+            margin-top: 20px;
+          }
+          th, td {
+            padding: 12px;
+            text-align: left;
+            border: 1px solid #ddd;
+            vertical-align: top;
+          }
+          th {
+            background-color: #f5f5f5;
+            font-weight: 600;
+          }
+          .config-value {
+            font-family: 'Courier New', monospace;
+            font-size: 12px;
+            white-space: pre-wrap;
+            word-break: break-all;
+            max-width: 400px;
+          }
+        </style>
+      </head>
+      <body>
+        <h1>Recommended Configuration Changes: Manual Review</h1>
+        
+        <table>
+          <thead>
+            <tr>
+              <th style="width: 15%;">Config Type</th>
+              <th style="width: 20%;">Property Name</th>
+              <th style="width: 32.5%;">Current Value</th>
+              <th style="width: 32.5%;">Recommended Value</th>
+            </tr>
+          </thead>
+          <tbody>
+            ${configs.map(config => `
+              <tr>
+                <td>${config.type}</td>
+                <td>${config.name}</td>
+                <td><div class="config-value">${config.currentValue}</div></td>
+                <td><div class="config-value">${config.recommendedValue}</div></td>
+              </tr>
+            `).join('')}
+          </tbody>
+        </table>
+      </body>
+      </html>
+    `;
+
+    const newTab = window.open('about:blank', '_blank');
+    
+    if (newTab) {
+      newTab.document.open();
+      newTab.document.write(htmlContent);
+      newTab.document.close();
+    } else {
+      toast.error('Unable to open new tab. Please check your browser settings.');
+    }
+  }
 
-          return allConfigs.concat({
+  function renderConfigurationTable(configs: any[]) {
+    const configTableColumns = [
+      {
+        accessorKey: "type",
+        header: "Config Type",
+        width: "10%",
+        cell: (info: any) => info.getValue(),
+      },
+      {
+        accessorKey: "name", 
+        header: "Property Name",
+        width: "20%",
+        cell: (info: any) => info.getValue(),
+      },
+      {
+        accessorKey: "currentValue",
+        header: "Current Value",
+        width: "35%",
+        cell: (info: any) => (
+          <div className="upgrade-recommend-config" >
+            <pre className="upgrade-recommend-config-pre">
+              {info.getValue()}
+            </pre>
+          </div>
+        ),
+      },
+      {
+        accessorKey: "recommendedValue",
+        header: "Recommended Value",
+        width: "35%",
+        cell: (info: any) => (
+          <div className="upgrade-recommend-config" >
+            <pre className="upgrade-recommend-config-pre">
+              {info.getValue()}
+            </pre>
+          </div>
+        ),
+      },
+    ];
+
+    return (
+      <div className="configuration-table-container">
+        <Table 
+          columns={configTableColumns} 
+          data={configs} 
+          showHeader={true} 
+          scrollable={true}
+          striped={true}
+        />
+      </div>
+    );
+  }
+
+  function getConfigsWarnings(configsMergeWarning: any) {
+    let configs = [];
+    if (
+      configsMergeWarning &&
+      configsMergeWarning.UpgradeChecks?.status === "WARNING"
+    ) {
+      const configsMergeCheckData =
+        configsMergeWarning.UpgradeChecks?.failed_detail;
+      if (configsMergeCheckData && Array.isArray(configsMergeCheckData)) {
+        configs = configsMergeCheckData.reduce((allConfigs, item) => {
+          const isDeprecated = item.new_stack_value == null;
+          const willBeRemoved = item.result_value == null;
+
+          return allConfigs.concat({
             type: item.type,
             name: item.property,
             wasModified:
@@ -1094,26 +963,374 @@ export default function Versions() {
     return configs;
   }
 
-  function runUpgradeMethodCheck(stack: StackVersion) {
-    const updateMethods = upgradeMethodsRef.current.map((method) => {
-      if (method.allowed) {
-        runPreUpgradeCheckOnly({
-          id: stack.ClusterStackVersions.id,
-          label: stack.repository_versions[0].RepositoryVersions.display_name,
-          type: method.type,
-        });
-      } else {
-        return {
-          ...method,
-          isCheckRequestInProgress: false,
-          isCheckComplete: false,
-          action: "",
-        };
-      }
-      return method;
-    });
+  async function runUpgradeMethodCheck(stack: StackVersion) {
+    const cacheKey = `${stack.ClusterStackVersions.id}-${stack.repository_versions[0].RepositoryVersions.repository_version}`;
+    
+    // Check if we have cached results
+    if (preCheckCacheRef.current.has(cacheKey)) {
+      const cachedResults = preCheckCacheRef.current.get(cacheKey);
+      upgradeMethodsRef.current = cachedResults;
+      setUpgradeMethods(cachedResults);
+      return;
+    }
+
+    const updateMethods = upgradeMethodsRef.current.map((method) => ({
+      ...method,
+      isCheckRequestInProgress: method.allowed,
+      isCheckComplete: false,
+    }));
     upgradeMethodsRef.current = updateMethods;
     setUpgradeMethods(updateMethods);
+
+    // Run all pre-upgrade checks in parallel for allowed methods
+    const allowedMethods = upgradeMethodsRef.current.filter(method => method.allowed);
+    const checkPromises = allowedMethods.map(method => 
+      runPreUpgradeCheckOnly({
+        id: stack.ClusterStackVersions.id,
+        label: stack.repository_versions[0].RepositoryVersions.display_name,
+        type: method.type,
+      }).catch(error => {
+        console.error(`Pre-upgrade check failed for ${method.type}:`, error);
+        // Return a default failed result
+        return {
+          methodType: method.type,
+          error: true,
+          precheckResultsMessage: "Check Failed",
+        };
+      })
+    );
+
+    try {
+      await Promise.all(checkPromises);
+      // Cache the results
+      preCheckCacheRef.current.set(cacheKey, upgradeMethodsRef.current);
+    } catch (error) {
+      console.error("Error running upgrade method checks:", error);
+    }
+  }
+
+  function installPackages() {
+    if (isOperationInProgress) {
+      setInstallPackagesModal(false);
+      return;
+    }
+
+    const initialOperations = [
+      {
+        id: "1",
+        label: "installing",
+        skippable: false,
+        context: "install packages",
+        callback: async () => {
+          const reqData = await RequestApi.installPackages(
+            clusterName,
+            packagesPayloadRef.current
+          );
+          return reqData;
+        },
+      },
+    ];
+    
+    setOperationsState(initialOperations);
+    setIsOperationInProgress(true);
+    
+    // Update stack state to show installation in progress
+    let selectedStackCopy = cloneDeep(selectedStack)
+    if (selectedStackCopy) {
+      set(selectedStackCopy, "ClusterStackVersions.state", "INSTALLING");
+      setSelectedStack(selectedStackCopy);
+      selectedStackRef.current = selectedStackCopy;
+    }
+
+    setAlertModal(false);
+    setInstallPackagesModal(false);
+  }
+
+  function getUpgradeStatus(stackData: StackVersion) {
+    const stackDisplayName = stackData.repository_versions[0].RepositoryVersions.display_name;
+    
+    if (upgradeState !== "COMPLETED" && upgradeState !== "NOT_REQUIRED" && upgradeVersionDisplayName && stackDisplayName === upgradeVersionDisplayName) {
+      return {
+        isUpgradeInProgress: true,
+        upgradeState: upgradeState,
+        statusText: getUpgradeRequestStatus(upgradeState, upgradeDirection == "DOWNGRADE"), // false for upgrade, true for downgrade
+      };
+    }
+    
+    return {
+      isUpgradeInProgress: false,
+      upgradeState: null,
+      statusText: null,
+    };
+  }
+
+  function getButtonName(stackData: StackVersion) {
+    const stackState = stackData.ClusterStackVersions.state;
+    if(getUpgradeStatus(stackData).isUpgradeInProgress) {
+      return "upgradeInProgress";
+    }
+    switch (stackState) {
+      case "CURRENT":
+        return "current";
+      case "INSTALL_FAILED":
+        return "re-install";
+      case "INSTALLED":
+        return "upgrade";
+      case "INSTALLING":
+        return "installing";
+      case "INTERMEDIATE":
+        return "intermediateInstalling";
+      default:
+        return "install_packages";
+    }
+  }
+
+  function getInstallPackageModalBody() {
+    const displayName =
+      selectedStackRef.current?.repository_versions?.[0]?.RepositoryVersions
+        ?.display_name || "N/A";
+    const isPatchSupported = selectedStackRef.current?.repository_versions?.[0]?.RepositoryVersions
+      ?.type === "PATCH";
+    
+    if(!isPatchSupported) {
+      return (
+        <div>
+          You are about to install packages for version 
+          <strong>{displayName}</strong> on all hosts.
+        </div>
+      );
+    } else {
+      return (
+        <div>
+          <div>You are about to install packages for version <strong>{displayName}</strong> on all hosts which contain the following servcies.</div>
+          <div className="mt-2">
+            <ul>
+              {Object.entries(selectedStackRef.current?.ClusterStackVersions.repository_summary.services || {}).map(([serviceName, serviceInfo]: [string, any]) => (
+                <li className="mt-1" key={serviceName}>{serviceName}: <Badge className="ms-2" bg="light">{serviceInfo.version}</Badge></li>
+              ))}
+            </ul>
+
+          </div>
+        </div>
+      )
+    }
+  }
+
+  function getVersionModalBody() {
+    if (!selectedStackRef.current || Object.keys(selectedStackRef.current).length === 0) {
+      return null;
+    }
+
+    const hostStates = selectedStackRef.current.ClusterStackVersions.host_states;
+    const installed = hostStates.INSTALLED.length;
+    const current = hostStates.CURRENT.length;
+    const notInstalled = (selectedStackRef.current.ClusterStackVersions.state === "NOT_REQUIRED") ? allHostNames.length : hostStates.INSTALL_FAILED.length + 
+                        hostStates.OUT_OF_SYNC.length + 
+                        hostStates.INSTALLING.length;
+    const notInstalledHosts = (selectedStackRef.current.ClusterStackVersions.state === "NOT_REQUIRED") ? allHostNames : [...hostStates.INSTALL_FAILED, ...hostStates.OUT_OF_SYNC, ...hostStates.INSTALLING];
+
+    return (
+      <div className="m-n2">
+        <div className="bg-info-subtle p-2">
+          <div className="d-flex justify-content-between">
+            <div></div>
+            <h2 className="text-dark ms-4">
+              {selectedStackRef.current?.repository_versions[0]?.RepositoryVersions
+                ?.display_name || "NA"}
+            </h2>
+            <h2 className="mx-2">
+                <Tooltip message="Click to Edit Repositories" placement="top">
+                  <FontAwesomeIcon
+                    className="fs-16 text-info"
+                    onClick={() =>
+                      modalManager.show(
+                        <RepoModal
+                          selectedStack={selectedStackRef.current}
+                          isOpen
+                          onClose={() => {
+                            modalManager.hide();
+                          }}
+                        />
+                      )
+                    }
+                    icon={faEdit}
+                  />
+                </Tooltip>
+            </h2>
+          </div>
+          <div className="mt-2 text-center mb-2">
+            <small className="text-muted">
+              (
+              {selectedStackRef.current?.repository_versions?.[0]?.RepositoryVersions
+                ?.repository_version || "NA"}
+              )
+            </small>
+          </div>
+            {selectedStackRef.current.repository_versions[0].RepositoryVersions.type === "PATCH" ? (
+            <div className="text-center mt-2 fs-6 text-warning">
+                <FontAwesomeIcon className="me-2" icon={faBug}/>
+                Patch
+            </div>
+          ) : (
+            <div className="mt-2 fs-6">&nbsp;</div>
+          )}
+          <div className="text-center mt-2">
+            {getButtonName(selectedStackRef.current) === "installing" ||
+            getButtonName(selectedStackRef.current) === "intermediateInstalling" ? (
+              isRestoring ? (
+                <Spinner />
+              ) :(
+                <Link to={""}>
+                  {renderOperationProgress()}
+                </Link>
+              )
+            ) : getButtonName(selectedStackRef.current) === "upgradeInProgress" ? (
+            <Button
+              variant="light"
+              size="sm"
+              className="custom-link color-white"
+              onClick={() => {
+                modalManager.show(<Upgrade upgradeId={upgradeId} />);
+              }}
+            >
+              {translate(getUpgradeStatus(selectedStackRef.current).statusText || "admin.stackUpgrade.state.inProgress")}
+            </Button>  
+            ) : getButtonName(selectedStackRef.current) === "upgrade" ? (
+              <Dropdown as={ButtonGroup} className="upgrade-dropdown popup">
+                <Button
+                  variant="success"
+                  size="sm"
+                  className="text-uppercase"
+                  disabled={!selectedStackRef.current || (upgradeState !== "NOT_REQUIRED" &&
+                  upgradeState !== "COMPLETED")}
+                  onClick={() => {
+                    if (selectedStackRef.current) {
+                      showUpgradeProceedButton.current = true;
+                      handleUpgradeClick(selectedStackRef.current);
+                    }
+                  }}
+                >
+                  Upgrade
+                </Button>
+                <Dropdown.Toggle
+                  split
+                  size="sm"
+                  variant="success"
+                  disabled={!selectedStackRef.current}
+                  id="dropdown-split-basic"
+                />
+                <Dropdown.Menu className="dropdown-menu-right">
+                  <Dropdown.Item
+                    disabled={!selectedStackRef.current || (upgradeState !== "NOT_REQUIRED" &&
+                    upgradeState !== "COMPLETED")}
+                    onClick={() => {
+                      if (selectedStackRef.current) {
+                        installPackagesPayloadSet(selectedStackRef.current);
+                      }
+                    }}
+                  >
+                    Re-install
+                  </Dropdown.Item>
+                  <Dropdown.Item
+                    disabled={!selectedStackRef.current || (upgradeState !== "NOT_REQUIRED" &&
+                    upgradeState !== "COMPLETED")}
+                    onClick={() => {
+                      showUpgradeProceedButton.current = false;
+                      if (selectedStackRef.current) {
+                        handleUpgradeClick(selectedStackRef.current);
+                      } else {
+                        toast.error("No stack selected for upgrade.");
+                      }
+                    }}
+                  >
+                    Pre-upgrade check
+                  </Dropdown.Item>
+                </Dropdown.Menu>
+              </Dropdown>
+            ) : (
+              <Button
+                className="text-uppercase"
+                variant="success"
+                size="sm"
+                disabled={!selectedStackRef.current}
+                onClick={() => {
+                  if (selectedStackRef.current) {
+                    handleUpgradeButton(selectedStackRef.current);
+                  }
+                }}
+              >
+                {getButtonName(selectedStackRef.current)}
+              </Button>
+            )}
+          </div>
+        </div>
+        <div className="pb-3">
+          <div className="text-center mt-3">Hosts</div>
+          <div className="d-flex justify-content-around mt-2">
+            <div>
+              <Button
+                variant="link"
+                onClick={() =>
+                  handleHostClick(
+                    "notInstalled",
+                    notInstalledHosts
+                  )
+                }
+                disabled={notInstalled === 0}
+              >
+                {notInstalled}
+              </Button>
+              <div>not installed</div>
+            </div>
+            <div>
+              <Button
+                variant="link"
+                onClick={() =>
+                  handleHostClick("installed", hostStates.INSTALLED)
+                }
+                disabled={installed === 0}
+              >
+                {installed}
+              </Button>
+              <div>installed</div>
+            </div>
+            <div>
+              <Button
+                variant="link"
+                onClick={() => handleHostClick("current", hostStates.CURRENT)}
+                disabled={current === 0}
+              >
+                {current}
+              </Button>
+              <div>current</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+  function handleHostClick(status: string, hosts: string[]) {
+    const versionStatus =
+      status === "current"
+        ? "Current"
+        : status === "installed"
+        ? "Installed"
+        : "Not installed";
+    const versionName =
+      selectedStackRef.current?.repository_versions[0]?.RepositoryVersions?.display_name ||
+      "N/A";
+    const hostList = hosts.join("\n\n");
+
+    hostModalContent.current = `${versionName} is ${versionStatus.toLowerCase() === "current" ? "applied": versionStatus.toLowerCase()} on ${
+      hosts.length
+    } hosts:\n\n\n${hostList}`;
+    hostModalTitle.current = `Version Status: ${versionStatus}`;
+    hostModalData.current = {
+      versionStatus: versionStatus === "Not installed" ? "NOT_INSTALLED" : versionStatus.toUpperCase(),
+      versionName: versionName,
+    };
+    setHostModal(true);
   }
 
   function getPreCheckResultsModalContent() {
@@ -1124,79 +1341,280 @@ export default function Versions() {
   }
 
   function getPreCheckModalTitle() {
-    return `Upgrade to ${selectedStackRef.current?.repository_versions[0].RepositoryVersions.display_name}`;
+    return `Upgrade to ${selectedStackRef.current?.repository_versions[0]?.RepositoryVersions?.display_name || "Unknown"}`;
   }
 
   function getUpgradConfirmationModalBody() {
     const stackVersion =
-      selectedStackRef.current?.repository_versions[0].RepositoryVersions.display_name;
-    return `You are about to perform an ${methodType} Upgrade to ${stackVersion}. This will incur cluster downtime. Are you sure you want to proceed?`;
+      selectedStackRef.current?.repository_versions[0]?.RepositoryVersions?.display_name || "Unknown";
+    if(methodType === "ROLLING") {
+      return (<div>{translateWithVariables("admin.stackVersions.version.upgrade.upgradeOptions.RU.confirm.msg", {"0": stackVersion})}</div>)
+    } else {
+      return (<div>{translateWithVariables("admin.stackVersions.version.upgrade.upgradeOptions.EU.confirm.msg", {"0": stackVersion})}</div>)
+    }
+  }
+
+  // Function to generate upgrade modal content
+  function getUpgradeModalContent() {
+    if (!selectedStackRef.current) return null;
+    
+    return (
+      <div className="upgrade-modal">
+        <div>
+          You are about to perform an upgrade to{" "}
+          <strong>
+            {selectedStackRef.current?.repository_versions[0]?.RepositoryVersions?.display_name || "Unknown"}
+          </strong>
+        </div>
+        <div className="pt-1">Choose the upgrade method:</div>
+
+        <div className="upgrade-options-container">
+          {upgradeMethods
+            .filter(
+              (method) =>
+                method.allowed && currentUpgradeTypes.includes(method.type)
+            )
+            .map((method) => (
+              <div
+                key={method.type}
+                className={`upgrade-method ${
+                  methodType === method.type ? "selected" : ""
+                }`}
+                onClick={() => handleMethodTypeSelection(method.type)}
+              >
+                <FontAwesomeIcon
+                  className="upgrade-method-icon"
+                  icon={iconMapping[method.icon]}
+                />
+                <div className="upgrade-method-title">{method.displayName}</div>
+                <div className="upgrade-method-description">
+                  {method.description}
+                </div>
+                <div
+                  className="upgrade-method-checks"
+                  onClick={(e) => {
+                    e.stopPropagation();
+                    showRerunButton.current = true;
+                    setUpgradeCheckModal(true);
+                    setMethodType(method.type);
+                  }}
+                >
+                  {method.isCheckRequestInProgress ? (
+                    <span>Loading checks...</span>
+                  ) : (
+                    <>
+                      {method.precheckResultsMessage.includes("Required") ? (
+                        <FontAwesomeIcon
+                          className="text-danger mx-1"
+                          icon={faTimes}
+                        />
+                      ) : (
+                        <FontAwesomeIcon
+                          className="text-warning mx-1"
+                          icon={faWarning}
+                        />
+                      )}
+                      Checks: {method.precheckResultsMessage}
+                    </>
+                  )}
+                </div>
+              </div>
+            ))}
+        </div>
+
+        <div className="upgrade-failure-tolerance">
+          <div>Select optional upgrade failure tolerance:
+            <Tooltip message={translate("admin.stackVersions.version.upgrade.upgradeOptions.tolerance.tooltip")}>
+              <FontAwesomeIcon
+                className="ms-1 custom-link"
+                icon={faQuestionCircle}
+              />
+            </Tooltip>
+          </div>
+          <Form className="pt-2">
+            <Form.Group controlId="serviceCheckFailures">
+              <Form.Check
+                type="checkbox"
+                label="Skip all Service Check failures"
+                checked={serviceCheckFailures}
+                onChange={(e) => setServiceCheckFailures(e.target.checked)}
+              />
+            </Form.Group>
+            <Form.Group controlId="slaveComponentFailures">
+              <Form.Check
+                type="checkbox"
+                label="Skip all Slave Component failures"
+                checked={slaveComponentFailures}
+                onChange={(e) => setSlaveComponentFailures(e.target.checked)}
+              />
+            </Form.Group>
+          </Form>
+        </div>
+
+        <div className="upgrade-warning">
+          Cluster alerts will still be visible and recorded in Ambari but
+          notifications (such as Email and SNMP) will be suppressed during the
+          upgrade.
+        </div>
+      </div>
+    );
   }
 
+  const columns = [
+    {
+      accessorKey: "name",
+      header: "",
+      cell: (info: any) => info.row.original,
+      width: "10%",
+    },
+  ];
+
   return (
     <>
+      {stackVersionError && (
+        <div className="alert alert-warning mt-3">
+          <div>
+            <div className="me-2">
+              <FontAwesomeIcon icon={faExclamationTriangle} />
+            </div>
+            <div>
+              <h4 className="display-inline me-1">{stackVersionError.title}</h4>
+              <span>{stackVersionError.stackFullName}</span>
+              <div>{stackVersionError.description}</div>
+            </div>
+          </div>
+        </div>
+      )}
       <div className="mt-4">
-        {/* TODO: Only show Manage versions button if user has CLUSTER.UPGRADE_DOWNGRADE_STACK permission */}
-        <Button
-          size="sm"
-          variant="success"
-          onClick={() => setManageVersionsModal(true)}
-        >
-          <FontAwesomeIcon className="mx-2" icon={faExternalLink} /> Manage
-          versions
-        </Button>
-        <Select
-          className="ms-3"
-          value={{
-            value: selectedOption.key,
-            label: `FILTER: ${selectedOption.key} (${selectedOption.count})`,
-          }}
-          onChange={handleSelectChange}
-          options={options.map((option) => {
-            return {
-              label: `${option.key} (${option.count})`,
-              value: option.key,
-            };
-          })}
-        />
-        <Table data={services} columns={columns} />
-      </div>
+        <div className="d-flex">
+             <Button
+                  size="sm"
+                  variant="success"
+                  onClick={() => setManageVersionsModal(true)}
+                >
+                  <FontAwesomeIcon className="mx-2" icon={faExternalLink} />{" "}
+                  Manage versions
+                </Button>
+               <Select
+               className="ms-3"
+                value={{
+                  value: selectedOption.key,
+                  label: `FILTER: ${selectedOption.key} (${selectedOption.count})`,
+                }}
+                onChange={handleSelectChange}
+                options={options.map((option) => {
+                  return {
+                    label: `${option.key} (${option.count})`,
+                    value: option.key,
+                  };
+                })}
+              />
+        </div>
 
-      <Modal
-        isOpen={versionModal}
-        onClose={() => setVersionModal(false)}
-        modalTitle="Version Details"
-        modalBody={getVersionModalBody()}
-        options={{
-          okButtonText: "DISMISS",
-          cancelableViaIcon: true,
-        }}
-        successCallback={() => setVersionModal(false)}
-      />
+        {stacks.length !== 0 ? (
+          <Row className="position-relative">
+            <Col md={3} className="mt-4">
+              <div className="version-services-table w-300 bg-transparent position-relative">
+                <Table columns={columns} data={services} showHeader={false} scrollable={false} />
+              </div>
+            </Col>
+            <Col md={9} className="versions-slides">
+              <div className="versions-slides-bar d-flex flex-nowrap">
+                {stacks.map((stackData: StackVersion) => {
+                  const isCurrent =
+                    stackData.ClusterStackVersions.state === "CURRENT";
+                  return (
+                    <div
+                      className={`version-box me-3${
+                        isCurrent ? " current" : ""
+                      }`}
+                    >
+                      {getStackHeader(stackData)}
+
+                      {services.map((service: any) => {
+                        const repoServices =
+                          stackData.repository_versions[0].RepositoryVersions
+                            .services;
+                        const matchingService = repoServices.find(
+                          (s: any) =>
+                            s.name === service ||
+                            s.name.toLowerCase() === service.toLowerCase()
+                        );
+                        if (matchingService?.versions?.[0]?.version) {
+                          const version = matchingService.versions[0].version;
+                          return (
+                            <div className="service-version-info text-center mt-3">
+                              <Badge className="bg-success position-relative fs-12 rounded-0">
+                                {version}
+                              </Badge>
+                            </div>
+                          );
+                        }
+                        const stackServices =
+                          stackData.repository_versions[0].RepositoryVersions
+                            .stack_services;
+                        const matchingStackService = stackServices.find(
+                          (s: any) =>
+                            s.name === service ||
+                            s.name.toLowerCase() === service.toLowerCase()
+                        );
+                        if (matchingStackService?.versions?.[0]) {
+                          const version = matchingStackService.versions[0];
+                          return (
+                            <div className="service-version-info text-center mt-3">
+                              <Badge bg="light" className="position-relative fs-12">
+                                {version}
+                              </Badge>
+                            </div>
+                          );
+                        }
+                        return (
+                          <div className="service-version-info text-center mt-3">
+                            <Badge bg="light" className="position-relative fs-12">
+                              UNKNOWN
+                            </Badge>
+                          </div>
+                        );
+                      })}
+                    </div>
+                  );
+                })}
+              </div>
+            </Col>
+          </Row>
+        ) : null}
+      </div>
 
-      <Modal
-        isOpen={repoModal}
-        onClose={() => setRepoModal(false)}
-        modalTitle="Repositories"
-        modalBody="Repository details will be shown here"
-        options={{
-          cancelableViaBtn: true,
-          okButtonText: "SAVE",
-        }}
-        successCallback={() => {}}
-      />
+      {versionModal ? (
+        <Modal
+          isOpen={versionModal}
+          onClose={() => setVersionModal(false)}
+          modalTitle="Version Details"
+          modalBody={getVersionModalBody()}
+          options={{
+            modalSize: "modal-sm",
+            okButtonText: "DISMISS",
+            cancelableViaIcon: true,
+            cancelableViaBtn: false,
+            modalBodyClassName: "p-0",
+          }}
+          successCallback={() => setVersionModal(false)}
+        />
+      ) : null}
 
-      <Modal
-        isOpen={installPackagesModal}
-        onClose={() => setInstallPackagesModal(false)}
-        modalTitle="Confirmation"
-        modalBody={getInstallPackageModalBody()}
-        options={{
-          cancelableViaBtn: true,
-          cancelableViaIcon: true,
-        }}
-        successCallback={() => installPackages()}
-      />
+      {installPackagesModal ? (
+        <Modal
+          isOpen={installPackagesModal}
+          onClose={() => setInstallPackagesModal(false)}
+          modalTitle="Confirmation"
+          modalBody={getInstallPackageModalBody()}
+          options={{
+            cancelableViaBtn: true,
+            cancelableViaIcon: true,
+          }}
+          successCallback={() => installPackages()}
+        />
+      ) : null}
 
       <Modal
         isOpen={hostModal}
@@ -1210,43 +1628,27 @@ export default function Versions() {
           cancelButtonText: "CLOSE",
         }}
         successCallback={() => {
-          "go to hosts";
+          navigate(
+            `/main/hosts/version/${hostModalData.current.versionName}/${hostModalData.current.versionStatus}`
+          );
         }}
       />
-      {manageVersionModal && (
-        <Modal
-          modalTitle="Manage Versions"
-          isOpen={manageVersionModal}
-          onClose={() => setManageVersionsModal(false)}
-          modalBody="You are about to leave the Cluster Management interface and go to the Ambari Administration interface. You can return to cluster management by using the “Go to Dashboard” link in the Ambari Administration > Clusters section."
-          options={{
-            cancelableViaBtn: true,
-            cancelableViaIcon: true,
-            okButtonText: "OK",
-            cancelButtonText: "CANCEL",
-          }}
-          successCallback={() => {
-            setManageVersionsModal(false);
-            // TODO: Redirect to admin view
-            // redirectToAdminView();
-          }}
-        />
-      )}
-
       <Modal
         isOpen={upgradeModal}
         onClose={() => setUpgradeModal(false)}
         modalTitle="Upgrade Options"
-        modalBody={upgradeModalContent.current}
+        modalBody={getUpgradeModalContent()}
+        className="upgrade-modal"
         options={{
           cancelableViaBtn: true,
           cancelableViaIcon: true,
+          cancelableViaSuccessBtn: showUpgradeProceedButton.current,
           okButtonText: "PROCEED",
           cancelButtonText: "CANCEL",
-          okButtonDisabled: !!upgradeOkButton.current,
+          okButtonDisabled: isProceedButtonDisabled,
         }}
         successCallback={() => {
-          if (showUpgradeProceedButton) {
+          if (showUpgradeProceedButton.current) {
             setUpgradeModal(false);
             setUpgradeConfirmationModal(true);
           }
@@ -1279,16 +1681,16 @@ export default function Versions() {
                 type: methodType,
               });
             } else {
-              const payload = JSON.stringify({
+              const payload = {
                 Upgrade: {
                   repository_version_id:
                     selectedStackRef.current?.repository_versions[0].RepositoryVersions.id,
                   upgrade_type: methodType,
-                  skip_failures: false,
-                  skip_service_check_failures: false,
+                  skip_failures: slaveComponentFailures.toString(),
+                  skip_service_check_failures: serviceCheckFailures.toString(),
                   direction: "UPGRADE",
                 },
-              });
+              };
               try {
                 const response = await VersionsApi.getUpgradeId(
                   payload,
@@ -1296,6 +1698,16 @@ export default function Versions() {
                 );
                 const upgradeId = response?.resources[0]?.Upgrade?.request_id;
                 setUpgradeId(upgradeId);
+                if(setIsPatchUpgrade) {
+                  const isPatch = get(selectedStackRef.current, "repository_versions[0].RepositoryVersions.type", "STANDARD") === "PATCH";
+                  setIsPatchUpgrade(isPatch);
+
+                  await ClusterApi.postPersistData(
+                    JSON.stringify({
+                      isPatchUpgrade: JSON.stringify(isPatch)
+                    })
+                  )
+                }
                 if(setUpgradeVersionDisplayName) {
                   const versionDisplayName = get(selectedStackRef.current, "repository_versions[0].RepositoryVersions.display_name", "");
                   setUpgradeVersionDisplayName(versionDisplayName);
@@ -1349,6 +1761,23 @@ export default function Versions() {
           }}
         />
       )}
+      {manageVersionModal && (
+        <Modal
+          modalTitle="Manage Versions"
+          isOpen={manageVersionModal}
+          onClose={() => setManageVersionsModal(false)}
+          modalBody="You are about to leave the Cluster Management interface and go to the Ambari Administration interface. You can return to cluster management by using the “Go to Dashboard” link in the Ambari Administration > Clusters section."
+          options={{
+            cancelableViaBtn: true,
+            cancelableViaIcon: true,
+            okButtonText: "OK",
+            cancelButtonText: "CANCEL",
+          }}
+          successCallback={() => {
+            // redirectToAdminView("stackVersions");
+          }}
+        />
+      )}
     </>
   );
 }
diff --git a/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/Upgrade.tsx b/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/Upgrade.tsx
index 9c2584e642..70761b3b34 100644
--- a/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/Upgrade.tsx
+++ b/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/Upgrade.tsx
@@ -18,6 +18,7 @@
 
 import { JSX, useContext, useState } from "react";
 import {
+  Alert,
   Badge,
   Button,
   Card,
@@ -27,16 +28,21 @@ import {
   Tab,
   Tabs,
 } from "react-bootstrap";
+import NestedCollapse from "../../../components/NestedCollapse";
 import _, { get } from "lodash";
 import Modal from "../../../components/Modal";
+import { useUpgrade } from "../../../hooks/useUpgrade";
 import Spinner from "../../../components/Spinner";
 import VersionsApi from "../../../api/VersionsApi";
 import { AppContext } from "../../../store/context";
 import toast from "react-hot-toast";
 import modalManager from "../../../store/ModalManager";
-import { getUpgradeDisplayName, translate, translateWithVariables } from "../../../Utils/Utility";
-import { useUpgrade } from "../../../hooks/useUpgrade";
-import NestedCollapse from "../../../components/NestedCollapse";
+import { getUpgradeDisplayName, initialUpgradeMethods, translate, translateWithVariables } from "../../../Utils/Utility";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faGears, faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
+import Tooltip from "../../../components/Tooltip";
+import ClusterApi from "../../../api/clusterApi";
+import { iconMapping } from "./ListVersion";
 
 type upgradeProps = {
   upgradeId: number;
@@ -67,9 +73,12 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
   const [confirmDowngradeModal, setConfirmDowngradeModal] = useState(false);
   const [pauseUpgradeModal, setPauseUpgradeModal] = useState(false);
   const [failedHostsModal, setFailedhostsModal] = useState(false);
+  const [upgradeOptionsModal, setUpgradeOptionsModal] = useState(false);
   const [localLogs, setLocalLogs] = useState<any>(null);
   const [localTasks, setLocalTasks] = useState<any[]>([]);
-  const { clusterName, setUpgradeState, setUpgradeId, isPatchUpgrade, upgradeVersionDisplayName } = useContext(AppContext);
+  const [slaveComponentFailures, setSlaveComponentFailures] = useState(upgradeParameters.slaveComponentFailures);
+  const [serviceCheckFailures, setServiceCheckFailures] = useState(upgradeParameters.serviceCheckFailures);
+  const { clusterName, setUpgradeState, setUpgradeId, isPatchUpgrade, upgradeVersionDisplayName, setUpgradeIsFinalizeItem } = useContext(AppContext);
 
   function getShowDetailsButton() {
     
@@ -100,7 +109,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                       variant="link"
                       onClick={() =>
                         handleCopy(
-                          logsToUse?.Tasks?.output_log ?? ""
+                          logsToUse?.Tasks?.stdout ?? ""
                         )
                       }
                     >
@@ -137,7 +146,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                       variant="link"
                       onClick={() =>
                         handleCopy(
-                          logsToUse?.Tasks?.error_log ?? ""
+                          logsToUse?.Tasks?.stderr ?? ""
                         )
                       }
                     >
@@ -171,7 +180,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
   }
 
   function getUpgradeModalTitle() {
-    return `${getUpgradeDisplayName(data?.Upgrade.upgrade_type || "rolling")} ${
+    const titleText = `${getUpgradeDisplayName(data?.Upgrade.upgrade_type || "rolling")} ${
       isPatchUpgrade ? "Patch" : ""
     } ${data?.Upgrade.direction} ${
       data?.Upgrade.direction == "DOWNGRADE" ? "from" : "to"
@@ -180,15 +189,40 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
         ? upgradeVersionDisplayName
         : data?.Upgrade.associated_version
     }`;
+    
+    return (
+      <div className="d-flex justify-content-between align-items-center w-100">
+        <span>{titleText}</span>
+        {!onlyView && (
+          <Button
+            variant="link"
+            size="sm"
+            disabled={upgradeParameters.isDowngrade}
+            className="p-0 ms-2 custom-link"
+            onClick={() => setUpgradeOptionsModal(true)}
+            title="Upgrade Options"
+          >
+            <FontAwesomeIcon icon={faGears} className="custom-link me-1" />
+            Upgrade Options
+          </Button>
+        )}
+      </div>
+    );
   }
 
   async function startDowngrade() {
-    const payload = JSON.stringify({
-      "Upgrade": {
+    setUpgradeIsFinalizeItem(false);
+    await ClusterApi.postPersistData(
+      JSON.stringify({
+        upgradeIsFinalizeItem: JSON.stringify(false)
+      })
+    )
+    const payload = {
+      "Upgrade": { 
         "upgrade_type": data?.Upgrade.upgrade_type,
         "direction": "DOWNGRADE",
       }
-    })
+    }
 
     try {
       const response = await VersionsApi.getUpgradeId(payload, clusterName);
@@ -198,6 +232,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
       setUpgradeModal(false);
       
       modalManager.show(<Upgrade upgradeId={downgradeId} />);
+      window.location.reload();
     } catch (error) {
       modalManager.show({
         modalTitle: "Upgrade could not be started",
@@ -245,19 +280,19 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
     } catch (error) {
       console.error("Error aborting upgrade:", error);
       if(upgradeParameters.isDowngrade) {
-        // const header = translate( "admin.stackDowngrade.state.paused.fail.header");
-        let body = translate( "admin.stackDowngrade.state.paused.fail.body");
+        // const header = get(messages, "admin.stackDowngrade.state.paused.fail.header");
+        let body = "Downgrade could not be paused. Try again later."
         if(error) {
           body = body + ' ' + error;
         }
-        toast(body.toString());
+        toast(body);
       } else {
-        // const header = translate( "admin.stackUpgrade.state.paused.fail.header");
-        let body = translate( "admin.stackUpgrade.state.paused.fail.body");
+        // const header = get(messages, "admin.stackUpgrade.state.paused.fail.header");
+        let body = "Downgrade could not be paused. Try again later."
         if(error) {
           body = body + ' ' + error;
         }
-        toast(body.toString());
+        toast(body);
       }
     }
   }
@@ -302,24 +337,66 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
     } catch (error) {
       console.error("Error aborting upgrade:", error);
       if(upgradeParameters.isDowngrade) {
-        let body = translate( "admin.stackDowngrade.state.paused.fail.body");
+        let body = "Downgrade could not be paused. Try again later.";
         if(error) {
           body = body + ' ' + error;
         }
-        toast(body.toString());
+        toast(body);
       } else {
-        let body = translate( "admin.stackUpgrade.state.paused.fail.body");
+        let body = "Downgrade could not be paused. Try again later.";
         if(error) {
           body = body + ' ' + error;
         }
-        toast(body.toString());
+        toast(body);
       }
     }
   }
 
   function getFailedHostsMessage(slaveComponentStructuredInfo: any) {
     const count = get(slaveComponentStructuredInfo, "hosts.length", 0);
-    return translateWithVariables("admin.stackUpgrade.failedHosts, showHosts", count);
+    return translateWithVariables("admin.stackUpgrade.failedHosts.showHosts", {"0": count});
+  }
+
+  function getFailedHostsModalBody() {
+    const hostInfo = upgradeParameters.slaveComponentStructuredInfo;
+    const hosts = hostInfo?.hosts || [];
+    const hostDetails = hostInfo?.host_detail || {};
+    
+    return (
+      <div className="failed-hosts-modal-content">
+        <div className="mb-3">
+          <div className="text-muted">Upgrade failed on {hosts.length} hosts</div>
+        </div>
+        
+        {hosts.map((hostname: string, index: number) => {
+          const hostComponents = hostDetails[hostname] || [];
+          return (
+            <div key={index} className="host-item mb-3">
+              <div className="d-flex align-items-center mb-2">
+                <span className="me-2">▶</span>
+                <span className="text-primary fw-bold">{hostname}</span>
+                <span className="badge bg-info text-white ms-2 rounded-pill">
+                  {hostComponents.length}
+                </span>
+              </div>
+              
+              <div className="ms-3">
+                <div className="row">
+                  {hostComponents.map((component: any, componentIndex: number) => (
+                    <div key={componentIndex} className="col-6 mb-2">
+                      <div className="p-2 border rounded">
+                        <div className="fw-bold">{component.service}</div>
+                        <div className="text-muted small">{component.component}</div>
+                      </div>
+                    </div>
+                  ))}
+                </div>
+              </div>
+            </div>
+          );
+        })}
+      </div>
+    );
   }
 
   function parseManualItemText(text: any) {
@@ -376,7 +453,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
     return (
       <>
         <div className="d-flex justify-content-between mb-4">
-          <div>{translate( `${upgradeParameters.upgradeStatusLabel}`)}</div>
+          <div>{translate(`${upgradeParameters.upgradeStatusLabel}`)}</div>
           <div className="d-flex">
             <ProgressBar
               now={data?.Upgrade.progress_percent}
@@ -392,7 +469,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
               onClick={() => setPauseUpgradeModal(true)}
             >
               {upgradeParameters.isDowngrade ? 
-                translate( "admin.stackUpgrade.pauseDowngrade") : translate( "admin.stackUpgrade.pauseUpgrade")
+                translate("admin.stackUpgrade.pauseDowngrade") : translate("admin.stackUpgrade.pauseUpgrade")
               }
             </Button>
           )}
@@ -400,10 +477,10 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
         <Card className="mb-4">
           <Card.Body>
             <div className="d-flex-column">
-            {upgradeParameters.runningItem && (
+            {upgradeParameters.runningItem && !onlyView && (
               <>
                 <div className="d-flex justify-content-between align-items-center">
-                  <div>{translate( "admin.stackUpgrade.dialog.inProgress")} {" "} {currUpgradeItem?.UpgradeItem.context}</div>
+                  <div>{translate("admin.stackUpgrade.dialog.inProgress")} {" "} {currUpgradeItem?.UpgradeItem.context}</div>
                   <Button
                     variant="link"
                     onClick={() => handleShowDetailsClick(currUpgradeItem)}
@@ -415,12 +492,12 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
               </>
             )}
 
-            {upgradeParameters.failedItem && !upgradeParameters.upgradeSuspended && !upgradeParameters.runningItem &&
+            {upgradeParameters.failedItem && !onlyView && !upgradeParameters.upgradeSuspended && !upgradeParameters.runningItem &&
             !upgradeParameters.isSlaveComponentFailuresItem ? (
               <>
                 <div className="d-flex justify-content-between">
                   <div>
-                    {translate( "admin.stackUpgrade.dialog.failed")}
+                    {translate("admin.stackUpgrade.dialog.failed")}
                     {upgradeParameters.failedItem.UpgradeItem.text}
                   </div>
                   <Button
@@ -436,8 +513,8 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                   <div>
                     {upgradeParameters.isDowngradeAvailable && (
                       <Button
-                        variant="link"
-                        className="text-uppercase"
+                        variant="danger"
+                        className="text-uppercase me-2"
                         disabled={upgradeParameters.requestInProgress}
                         onClick={() => setConfirmDowngradeModal(true)}
                       >
@@ -447,7 +524,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                     {upgradeParameters.canSkipFailedItem && (
                       <Button
                         variant="warning"
-                        className="text-uppercase"
+                        className="text-uppercase me-2"
                         disabled={upgradeParameters.requestInProgress}
                         onClick={() => {
                             if(currUpgradeItem) {
@@ -459,7 +536,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                           }
                         }
                       >
-                        {translate( "admin.stackUpgrade.dialog.continue")}
+                        {translate("admin.stackUpgrade.dialog.continue")}
                       </Button>
                     )} 
                     <Button
@@ -472,100 +549,114 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                       }
                       }
                     >
-                      {translate( "common.retry")}
+                      {translate("common.retry")}
                     </Button>
                   </div>
                 </div>
               </>
             ) : null}
 
-            { upgradeParameters.isSlaveComponentFailuresItem && !upgradeParameters.upgradeSuspended && 
+            { upgradeParameters.isSlaveComponentFailuresItem && !onlyView && !upgradeParameters.upgradeSuspended && 
               <>
-                <div>
-                  <div>{translate( "admin.stackUpgrade.dialog.manual")}</div>
+                <div className="manual-steps-section">
+                  <div className="manual-steps-title">{translate("admin.stackUpgrade.dialog.manual")}</div>
+                  <div className="upgrade-failed-message">
+                    {translate("admin.stackUpgrade.failedHosts.message")}
+                  </div>
                   {upgradeParameters.areSlaveComponentFailuresHostsLoaded ? (
-                    <div>
-                      <div>{translate( "admin.stackUpgrade.failedHosts.message")}</div>
-                      <Badge onClick={() => setFailedhostsModal(true)} >{getFailedHostsMessage(upgradeParameters.slaveComponentStructuredInfo)}</Badge>
+                    <div className="failed-hosts-info">
+                      <span 
+                        className="custom-link" 
+                        onClick={() => setFailedhostsModal(true)}
+                      >
+                        {getFailedHostsMessage(upgradeParameters.slaveComponentStructuredInfo)}
+                      </span>
                     </div>
                   ) : <Spinner />}
-                  <div>
-                    <p>{translate( "admin.stackUpgrade.failedHosts.options")}</p>
-                    <ul>
-                      <li>{translate("admin.stackUpgrade.failedHosts.options.first")}</li>
-                      <li>{translate("admin.stackUpgrade.failedHosts.options.second")}</li>
+                  <div className="upgrade-options mt-2">
+                    <div className="options-title">{translate("admin.stackUpgrade.failedHosts.options")}</div>
+                    <ul className="options-list mt-2">
+                      <li className="mt-1">{translate("admin.stackUpgrade.failedHosts.options.first")}</li>
+                      <li className="mt-1">{translate("admin.stackUpgrade.failedHosts.options.second")}</li>
                     </ul>
                   </div>
                   {!upgradeParameters.isHoldingState && (
-                    <Form className="mx-2">
-                      <Form.Group controlId="manualCheck">
-                        <Form.Check
-                          type="checkbox"
-                          checked={isManualDone}
-                          onChange={() => setManualDone(!isManualDone)}
-                          label={translate(
-                            "admin.stackUpgrade.dialog.manualDone"
-                          )}
-                        />
-                      </Form.Group>
-                    </Form>
+                    <div className="manual-checkbox-container">
+                      <Form.Check
+                        type="checkbox"
+                        checked={isManualDone}
+                        onChange={() => setManualDone(!isManualDone)}
+                        label={translate("admin.stackUpgrade.dialog.manualDone")}
+                        className="manual-done-checkbox"
+                      />
+                    </div>
                   )}
                 </div>
-                <div className="justify-content-between">
-                    {upgradeParameters.isDowngradeAvailable ? (
+                <div className="d-flex justify-content-between mt-3">
+                  <div></div>
+                  <div>
+                    {upgradeParameters.isDowngradeAvailable && (
                       <Button
                         variant="danger"
+                        size="sm"
+                        className="me-2"
                         onClick={() => setConfirmDowngradeModal(true)}
                         disabled={upgradeParameters.requestInProgress}
                       >
-                        {translate( "common.downgrade")}
+                        {translate("common.downgrade")}
                       </Button>
-                    ) : null}
+                    )}
                     <Button
-                      variant="primary"
+                      variant="success"
+                      size="sm"
+                      className="me-2"
                       onClick={() => {
                         if(currUpgradeItem)
                           setUpgradeItemStatus(currUpgradeItem, "PENDING")
-                      }
-                      }
+                      }}
+                      disabled={upgradeParameters.requestInProgress}
                     >
-                      {translate( "common.retry")}
+                      {translate("common.retry")}
                     </Button>
                     <Button
-                      variant="primary"
+                      variant="success"
+                      size="sm"
                       onClick={() => {
+                        setManualDone(false);
                         if(currUpgradeItem)
                           setUpgradeItemStatus(currUpgradeItem, "COMPLETED")
-                      }
-                      }
+                      }}
+                      disabled={upgradeParameters.requestInProgress || !isManualDone}
                     >
-                      {translate( "common.proceed")}
+                      {translate("common.proceed")}
                     </Button>
                   </div>
+                  
+                </div>
               </>
             }
 
-            { upgradeParameters.isServiceCheckFailuresItem && !upgradeParameters.upgradeSuspended && 
+            { upgradeParameters.isServiceCheckFailuresItem && !onlyView && !upgradeParameters.upgradeSuspended && 
               <>
                 <div>
-                  <div>{translate( "admin.stackUpgrade.dialog.manual")}</div>
+                  <div>{translate("admin.stackUpgrade.dialog.manual")}</div>
                   {upgradeParameters.areServiceCheckFailuresServicenamesLoaded ? (
                     upgradeParameters.serviceCheckFailuresServicenames.length ? (
                       <div>
-                        <div>{translate( "admin.stackUpgrade.dialog.manual.serviceCheckFailures.title")}</div>
-                        <div>{translate( "admin.stackUpgrade.dialog.manual.serviceCheckFailures.msg1")}</div>
+                        <div>{translate("admin.stackUpgrade.dialog.manual.serviceCheckFailures.title")}</div>
+                        <div>{translate("admin.stackUpgrade.dialog.manual.serviceCheckFailures.msg1")}</div>
                         <ul className="failed-info-list">
                           {upgradeParameters.serviceCheckFailuresServicenames.map((serviceName: any, index: any) => (
                             <li key={index}>{serviceName}</li>
                           ))}
                         </ul>
-                        <div>{translate( "admin.stackUpgrade.dialog.manual.serviceCheckFailures.msg2")}</div>
+                        <div>{translate("admin.stackUpgrade.dialog.manual.serviceCheckFailures.msg2")}</div>
                       </div>
                     ) : upgradeParameters.slaveComponentStructuredInfo.hosts.length ? (
                       <div>
-                        <div>{translate( "admin.stackUpgrade.dialog.manual.slaveComponentFailures.title")}</div>
+                        <div>{translate("admin.stackUpgrade.dialog.manual.slaveComponentFailures.title")}</div>
                         <div>
-                          <div>{translate( "admin.stackUpgrade.failedHosts.message")}</div>
+                          <div>{translate("admin.stackUpgrade.failedHosts.message")}</div>
                           <Badge onClick={() => setFailedhostsModal(true)}>
                             {getFailedHostsMessage(upgradeParameters.slaveComponentStructuredInfo)}
                           </Badge>
@@ -606,31 +697,34 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                       {upgradeParameters.isDowngradeAvailable ? (
                         <Button
                           variant="danger"
+                          className="me-2"
                           onClick={() => setConfirmDowngradeModal(true)}
                           disabled={upgradeParameters.requestInProgress}
                         >
-                          {translate( "common.downgrade")}
+                          {translate("common.downgrade")}
                         </Button>
                       ) : null}
                       <Button
                         variant="primary"
+                        className="me-2"
                         onClick={() => {
+                          setManualDone(false);
                           if(currUpgradeItem)
                             setUpgradeItemStatus(currUpgradeItem, "PENDING")
                         }
                         }
                       >
-                        {translate( "common.retry")}
+                        {translate("common.retry")}
                       </Button>
                     </div>
                   </div>
               </>
             }
 
-            {upgradeParameters.isFinalizeItem && !upgradeParameters.upgradeSuspended ? (
+            {upgradeParameters.isFinalizeItem && !onlyView && !upgradeParameters.upgradeSuspended ? (
               <>
                 <div className="mb-2">
-                  <div className="text-dark mb-2">{translate( "admin.stackUpgrade.dialog.manual")}</div>
+                  <div className="text-dark mb-2">{translate("admin.stackUpgrade.dialog.manual")}</div>
                   {upgradeParameters.isDowngrade ? (
                     <p className="manual-steps-content">
                       {translate(
@@ -695,6 +789,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                         className="ms-2"
                         disabled={!isManualDone}
                         onClick={() => {
+                          setManualDone(false);
                           if(currUpgradeItem)
                             setUpgradeItemStatus(currUpgradeItem, "COMPLETED")
                         }
@@ -708,10 +803,10 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
               </>
             ) : null}
 
-            {upgradeParameters.plainManualItem && !upgradeParameters.isFinalizeItem && !upgradeParameters.upgradeSuspended ? (
+            {upgradeParameters.plainManualItem && !upgradeParameters.isFinalizeItem && !onlyView && !upgradeParameters.upgradeSuspended ? (
               <div>
                 <div className="mb-3">
-                  <div className="me-2 mt-1 text-dark">{translate( "admin.stackUpgrade.dialog.manual")}</div>
+                  <div className="me-2 mt-1 text-dark">{translate("admin.stackUpgrade.dialog.manual")}</div>
                   {upgradeParameters.manualItem?.UpgradeItem.text && upgradeParameters.manualItem.UpgradeItem.text.length > 0 ? (
                     parseManualItemText(upgradeParameters.manualItem.UpgradeItem.text).map((item, index) => {
                       return (
@@ -745,7 +840,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                         onClick={() => setConfirmDowngradeModal(true)}
                         disabled={upgradeParameters.requestInProgress}
                       >
-                        {translate( "common.downgrade")}
+                        {translate("common.downgrade")}
                       </Button>
                     ) : null}
                     <Button
@@ -753,6 +848,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                       className="mx-2"
                       disabled={!isManualDone}
                       onClick={() => {
+                        setManualDone(false);
                         if(currUpgradeItem)
                           setUpgradeItemStatus(currUpgradeItem, "COMPLETED")
                       }
@@ -770,9 +866,9 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                 <div className="d-flex justify-content-between">
                 <div className="mt-3">
                   {upgradeParameters.isDowngrade ? (
-                    <label>{translate( "admin.stackUpgrade.dialog.suspended.downgrade")}</label>
+                    <label>{translate("admin.stackUpgrade.dialog.suspended.downgrade")}</label>
                   ) : (
-                    <label>{translate( "admin.stackUpgrade.dialog.suspended")}</label>
+                    <label>{translate("admin.stackUpgrade.dialog.suspended")}</label>
                   )}
                 </div>
 
@@ -780,12 +876,16 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
                   <Button
                     variant="primary"
                     onClick={() => resumeUpgrade()}
-                  >{translate( "admin.stackUpgrade.dialog.resume.downgrade")}</Button>
+                  >
+                    {translate("admin.stackUpgrade.dialog.resume.downgrade")}
+                  </Button>
                 ) : (
                   <Button
                     variant="primary"
                     onClick={() => resumeUpgrade()}
-                  >{translate( "admin.stackUpgrade.dialog.resume")}</Button>
+                  >
+                    {translate("admin.stackUpgrade.dialog.resume")}
+                  </Button>
                 )}
               </div>
             </>
@@ -810,6 +910,7 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
           fetchLogs={fetchLogs}
           handleCopy={handleCopy}
           handleOpenInNewTab={handleOpenInNewTab}
+          onlyView={onlyView}
         />
       </>
     );
@@ -829,6 +930,100 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
       ? translate("admin.stackUpgrade.pauseDowngrade") 
       : translate("admin.stackUpgrade.pauseUpgrade");
   }
+
+  // Function to update upgrade options during active upgrade
+  async function updateUpgradeOptions() {
+    if (!upgradeId) {
+      toast.error("No active upgrade found");
+      return;
+    }
+
+    const payload = {
+      Upgrade: {
+        skip_failures: slaveComponentFailures.toString(),
+        skip_service_check_failures: serviceCheckFailures.toString(),
+      },
+    };
+
+    try {
+      await VersionsApi.updateUpgrade(upgradeId, payload, clusterName);
+      toast.success("Upgrade options updated successfully");
+      setUpgradeOptionsModal(false);
+    } catch (error) {
+      toast.error("Failed to update upgrade options");
+      console.error("Error updating upgrade options:", error);
+    }
+  }
+
+  // Function to generate upgrade options modal content (for active upgrades)
+  function getUpgradeOptionsModalContent() {
+    
+    return (
+      <div className="upgrade-modal">
+        <div>Choose the upgrade method:</div>
+        
+        <div className="upgrade-options-container">
+          {initialUpgradeMethods
+            .filter(
+              (method: any) =>
+                method.allowed
+            )
+            .map((method: any) => (
+              <div
+                key={method.type}
+                className={`upgrade-method disabled ${
+                  upgradeParameters.upgradeMethod === method.type ? "selected" : ""
+                }`}
+              >
+                <FontAwesomeIcon
+                  className="upgrade-method-icon"
+                  icon={iconMapping[method.icon]}
+                />
+                <div className="upgrade-method-title">{method.displayName}</div>
+                <div className="upgrade-method-description">
+                  {method.description}
+                </div>
+              </div>
+            ))}
+        </div>
+
+        <div className="upgrade-failure-tolerance mt-4">
+          <div>Select optional upgrade failure tolerance:
+            <Tooltip message={translate("admin.stackVersions.version.upgrade.upgradeOptions.tolerance.tooltip")}>
+              <FontAwesomeIcon
+                className="ms-1 custom-link cursor-pointer"
+                icon={faQuestionCircle}
+              />
+            </Tooltip>
+          </div>
+          <Form className="pt-2">
+            <Form.Group controlId="serviceCheckFailures">
+              <Form.Check
+                type="checkbox"
+                label="Skip all Service Check failures"
+                checked={serviceCheckFailures}
+                onChange={(e) => setServiceCheckFailures(e.target.checked)}
+              />
+            </Form.Group>
+            <Form.Group controlId="slaveComponentFailures">
+              <Form.Check
+                type="checkbox"
+                label="Skip all Slave Component failures"
+                checked={slaveComponentFailures}
+                onChange={(e) => setSlaveComponentFailures(e.target.checked)}
+              />
+            </Form.Group>
+          </Form>
+        </div>
+
+        <Alert variant="warning" className="mt-3">
+          Cluster alerts will still be visible and recorded in Ambari but
+          notifications (such as Email and SNMP) will be suppressed during the
+          upgrade.
+        </Alert>
+      </div>
+    );
+  }
   
   return (
     <>
@@ -895,16 +1090,33 @@ export default function Upgrade({ upgradeId, onlyView=false, onClose }: upgradeP
         <Modal
         isOpen={failedHostsModal}
         onClose={() => setFailedhostsModal(false)}
-        modalTitle={translate( "admin.stackUpgrade.failedHosts.header")}
-        modalBody={upgradeParameters.slaveComponentStructuredInfo}
+        modalTitle={translate("admin.stackUpgrade.failedHosts.header")}
+        modalBody={getFailedHostsModalBody()}
         options={{
-          okButtonText: translate( "common.close"),
+          okButtonText: translate("common.close"),
           modalSize: "modal-sm",
           cancelableViaIcon: true,
         }}
         successCallback={() => setFailedhostsModal(false)}
         />
       )}
+
+      {upgradeOptionsModal && (
+        <Modal
+          isOpen={upgradeOptionsModal}
+          onClose={() => setUpgradeOptionsModal(false)}
+          modalTitle="Upgrade Options"
+          modalBody={getUpgradeOptionsModalContent()}
+          options={{
+            modalSize: "modal-sm",
+            cancelableViaBtn: true,
+            cancelableViaIcon: true,
+            okButtonText: "OK",
+            cancelButtonText: "CANCEL",
+          }}
+          successCallback={() => updateUpgradeOptions()}
+        />
+      )}
     </>
   );
-}
\ No newline at end of file
+}
diff --git a/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/types.ts b/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/types.ts
index e32ff9612e..f9d82b99b5 100644
--- a/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/types.ts
+++ b/ambari-web/latest/src/screens/ClusterAdmin/StackAndVersions/types.ts
@@ -39,25 +39,25 @@ type RepositoryVersion = {
     };
   };
   operating_systems: OperatingSystem[];
-}
+};
 
 type Service = {
   name: string;
   versions: Version[];
   display_name: string;
-}
+};
 
 type Version = {
   version: string;
   components: any[];
-}
+};
 
 type StackService = {
   name: string;
   display_name: string;
   comment: string;
   versions: string[];
-}
+};
 
 type OperatingSystem = {
   href: string;
@@ -69,7 +69,7 @@ type OperatingSystem = {
     stack_version: string;
   };
   repositories: Repository[];
-}
+};
 
 type Repository = {
   href: string;
@@ -90,7 +90,7 @@ type Repository = {
     tags: any[];
     unique: boolean;
   };
-}
+};
 
 type ClusterStackVersion = {
   cluster_name: string;
@@ -108,6 +108,7 @@ type ClusterStackVersion = {
   stack: string;
   state: string;
   supports_revert: boolean;
+  revert_upgrade_id: number | null;
   version: string;
   host_states: {
     CURRENT: string[];
@@ -117,13 +118,13 @@ type ClusterStackVersion = {
     NOT_REQUIRED: string[];
     OUT_OF_SYNC: string[];
   };
-}
+};
 
 type StackVersion = {
   href: string;
   ClusterStackVersions: ClusterStackVersion;
   repository_versions: RepositoryVersion[];
-}
+};
 
 type UpgradeCheck = {
   check: string;
@@ -140,17 +141,17 @@ type UpgradeCheck = {
   repository_version_id: number;
   status: string;
   upgrade_type: string;
-}
+};
 
 type Item = {
   href: string;
   UpgradeChecks: UpgradeCheck;
-}
+};
 
 type Response = {
   href: string;
   items: Item[];
-}
+};
 
 type ClusterCheckPopupData = {
   header: any;
@@ -161,7 +162,7 @@ type ClusterCheckPopupData = {
   primary: any;
   secondary: any;
   bypassedFailures: boolean;
-}
+};
 
 type TaskLog = {
   Tasks: {
@@ -238,7 +239,7 @@ type UpgradeGroup = {
     status: string;
     title: string;
     total_task_count: number;
-  },
+  };
   upgrade_items: UpgradeItem[];
 };
 
@@ -300,25 +301,28 @@ type UpgradeParameters = {
   upgradeRunning: boolean;
   showPauseButton: boolean;
   upgradeStatusLabel: string;
-  upgradeAssociatedversion: string
+  upgradeAssociatedversion: string;
+  slaveComponentFailures: boolean;
+  serviceCheckFailures: boolean;
+  upgradeMethod: string;
 };
 
 export type {
-    RepositoryVersion,
-    Service,
-    Version,
-    StackService,
-    OperatingSystem,
-    Repository,
-    ClusterStackVersion,
-    StackVersion,
-    UpgradeCheck,
-    Item,
-    Response,
-    ClusterCheckPopupData,
-    UpgradeData,
-    UpgradeGroup,
-    UpgradeItem,
-    Task,
-    UpgradeParameters
+  RepositoryVersion,
+  Service,
+  Version,
+  StackService,
+  OperatingSystem,
+  Repository,
+  ClusterStackVersion,
+  StackVersion,
+  UpgradeCheck,
+  Item,
+  Response,
+  ClusterCheckPopupData,
+  UpgradeData,
+  UpgradeGroup,
+  UpgradeItem,
+  Task,
+  UpgradeParameters,
 };
\ No newline at end of file
diff --git a/ambari-web/latest/src/store/context.tsx b/ambari-web/latest/src/store/context.tsx
index 8510dbdd1a..bedd4763e0 100644
--- a/ambari-web/latest/src/store/context.tsx
+++ b/ambari-web/latest/src/store/context.tsx
@@ -66,6 +66,8 @@ interface AppContextProps {
   setIsPatchUpgrade?: (isPatch: boolean) => void;
   upgradeVersionDisplayName?: string;
   setUpgradeVersionDisplayName?: (name: string) => void;
+  upgradeIsFinalizeItem: boolean;
+  setUpgradeIsFinalizeItem: (isFinalize: boolean) => void;
   userUrl?: string;
   sessionsValidated: boolean;
   sessionExists: boolean;
@@ -100,6 +102,8 @@ export const AppContext = createContext<AppContextProps>({
   setIsPatchUpgrade: () => {},
   upgradeVersionDisplayName: "",
   setUpgradeVersionDisplayName: () => {},
+  upgradeIsFinalizeItem: false,
+  setUpgradeIsFinalizeItem: () => {},
   sessionExists: false,
   sessionsValidated: false,
   clusterState: {}
@@ -121,6 +125,7 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({
   const [upgradeDirection, setUpgradeDirection] = useState<string>("");
   const [upgradeSuspend, setUpgradeSuspend] = useState<boolean>(false);
   const [upgradeId, setUpgradeId] = useState<number>(0);
+  const [upgradeIsFinalizeItem, setUpgradeIsFinalizeItem] = useState<boolean>(false);
   const [isPatchUpgrade, setIsPatchUpgrade] = useState<boolean>(false);
   const [upgradeVersionDisplayName, setUpgradeVersionDisplayName] = useState<string>("");
   const [currentStackVersion, setCurrentStackVersion] = useState<string>("");
@@ -336,6 +341,9 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({
     const isPatch = await ClusterApi.getPersistData("isPatchUpgrade");
     setIsPatchUpgrade(isPatch);
 
+    const isFinalizeItem = await ClusterApi.getPersistData("upgradeIsFinalizeItem");
+    setUpgradeIsFinalizeItem(isFinalizeItem);
+
     const upgradeVersionDisplayName = await ClusterApi.getPersistData("upgradeVersionDisplayName");
     setUpgradeVersionDisplayName(upgradeVersionDisplayName);
   };
@@ -497,6 +505,8 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({
         setIsPatchUpgrade,
         upgradeVersionDisplayName,
         setUpgradeVersionDisplayName,
+        upgradeIsFinalizeItem,
+        setUpgradeIsFinalizeItem,
         userUrl,
         sessionExists,
         sessionsValidated,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ambari.apache.org
For additional commands, e-mail: commits-help@ambari.apache.org