You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by vi...@apache.org on 2026/05/18 09:00:56 UTC

(ambari) branch frontend-refactor updated: AMBARI-26369 : Ambari Web React: Hosts Configs Page (#4130)

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

vishalsuvagia 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 00830d8e3e AMBARI-26369 : Ambari Web React: Hosts Configs Page (#4130)
00830d8e3e is described below

commit 00830d8e3e90033d621443e48dc325c3206b4a13
Author: Himanshu Maurya <54...@users.noreply.github.com>
AuthorDate: Mon May 18 14:30:51 2026 +0530

    AMBARI-26369 : Ambari Web React: Hosts Configs Page (#4130)
    
    Co-authored-by : Kowshic-V
---
 ambari-web/latest/package.json                     |    1 +
 .../Initializers/AddComponentConfigInitializer.ts  |  556 ++++
 .../AddHiveComponentsInitializer.ts}               |   27 +-
 .../AddZooKeeperComponentsInitializer.ts           |   58 +
 .../latest/src/Initializers/ConfigInitializer.ts   |  128 +
 .../src/Initializers/ControlFlowInitializer.ts     |  136 +
 .../HaConfigInitializer.ts}                        |   33 +-
 .../src/Initializers/HostsBasedInitializer.ts      |  331 +++
 .../Initializers/MoveComponentConfigInitializer.ts |  259 ++
 .../MoveHiveComponentConfigInitializer.ts          |   99 +
 .../src/Initializers/MoveHmConfigInitializer.ts    |  143 +
 .../src/Initializers/MoveHsConfigInitializer.ts    |   72 +
 .../Initializers/MoveNameNodeConfigInitializer.ts  |  243 ++
 .../src/Initializers/MoveOSConfigInitializer.ts    |   69 +
 .../src/Initializers/MoveRmConfigInitializer.ts    |  195 ++
 .../src/Initializers/MoveWsConfigInitializer.ts    |   72 +
 .../src/Initializers/UtilitiesForInitialziers.ts   |  168 ++
 .../src/Initializers/WizardConfigInitializer.ts    |  632 ++++
 ambari-web/latest/src/Utils/StringUtilsObj.ts      |  173 ++
 ambari-web/latest/src/Utils/Utility.ts             |  554 +++-
 ambari-web/latest/src/Utils/adminViewRedirect.ts   |   50 +
 ambari-web/latest/src/Utils/cacheUtils.ts          |   86 +
 ambari-web/latest/src/Utils/clusterConfigUtils.ts  |  121 +
 ambari-web/latest/src/Utils/configs.ts             |  456 +++
 ambari-web/latest/src/Utils/credentialsUtils.ts    |  153 +
 .../DirectoriesTab.tsx => Utils/jvmFormatUtils.ts} |   16 +-
 ambari-web/latest/src/Utils/sslProtocolUtils.ts    |  287 ++
 ambari-web/latest/src/Utils/unitConversionUtils.ts |  358 +++
 ambari-web/latest/src/api/AssignMastersApi.ts      |   58 -
 .../src/api/{ActionsApi.ts => actionsApi.ts}       |    0
 ambari-web/latest/src/api/adminApi.ts              |   73 +
 ambari-web/latest/src/api/assignMastersApi.ts      |   50 +
 ambari-web/latest/src/api/cachedServiceApi.ts      |  216 ++
 .../latest/src/api/centralizedServiceStateApi.ts   |  153 +
 ambari-web/latest/src/api/chooseServicesApi.ts     |    1 +
 ambari-web/latest/src/api/clusterApi.ts            |   24 +-
 ambari-web/latest/src/api/clusterDeployment.ts     |   67 +
 .../src/api/{validations.ts => componentApi.ts}    |   16 +-
 ambari-web/latest/src/api/config/axiosConfig.ts    |    1 +
 .../src/api/{LogApi.ts => configHistoryApi.ts}     |   20 +-
 ambari-web/latest/src/api/credentialsApi.ts        |   97 +
 ambari-web/latest/src/api/hostsApi.ts              |   42 +
 ambari-web/latest/src/api/kerberosApi.ts           |   68 +-
 ambari-web/latest/src/api/{LogApi.ts => logApi.ts} |    1 +
 ambari-web/latest/src/api/loginApi.ts              |    1 +
 ambari-web/latest/src/api/metricsApi.ts            |  164 +-
 ambari-web/latest/src/api/nameNodeFederationApi.ts |   56 +
 .../src/api/{validations.ts => persistanceApi.ts}  |    9 +-
 .../{recommendationsApi.ts => quicklinksApi.ts}    |   24 +-
 ambari-web/latest/src/api/recommendationsApi.ts    |    1 +
 ambari-web/latest/src/api/requestApi.ts            |   10 +-
 .../src/api/{ServiceApi.ts => serviceApi.ts}       |    1 +
 ambari-web/latest/src/api/serviceConfigApi.ts      |   38 +
 ambari-web/latest/src/api/validations.ts           |    1 +
 .../src/api/{VersionsApi.ts => versionsApi.ts}     |  257 +-
 .../latest/src/api/{LogApi.ts => viewApi.tsx}      |   21 +-
 ambari-web/latest/src/api/wizardApi.ts             |    2 +-
 ambari-web/latest/src/components/AssignMasters.tsx |  534 ++--
 .../latest/src/components/AssignMastersAddable.tsx | 1670 +++++++++++
 .../latest/src/components/ConfirmationModal.tsx    |    7 +-
 ambari-web/latest/src/components/CustomSlider.tsx  |  109 +
 .../components/DependentConfigurationsModal.tsx    |  225 ++
 .../latest/src/components/InvalidKdcPopup.tsx      |  111 +
 .../OverlayBackdrop.tsx}                           |   17 +-
 ambari-web/latest/src/components/RepoModal.tsx     |    2 +-
 ambari-web/latest/src/constants.ts                 |  405 +--
 .../src/data/configs/kerberos_ui_properties.ts     |    1 +
 .../Step7/DatabasesTab.tsx => enums/Categories.ts} |   12 +-
 ambari-web/latest/src/enums/ComponentNameEnums.ts  |   86 +
 ambari-web/latest/src/enums/ServiceActionEnums.ts  |   66 +
 .../src/enums/ServiceComponentMetricsEnums.ts      |  306 ++
 ambari-web/latest/src/hooks/useAuth.ts             |    1 +
 ambari-web/latest/src/hooks/useConfigSaver.tsx     |  694 +++++
 ambari-web/latest/src/hooks/useConfigs.ts          |    3 +-
 ambari-web/latest/src/hooks/useConfigsTags.ts      |  305 ++
 ambari-web/latest/src/hooks/useCopyToClipboard.ts  |    1 +
 ambari-web/latest/src/hooks/useDebounce.ts         |    1 +
 ambari-web/latest/src/hooks/useDecommissionable.ts |   14 +-
 ambari-web/latest/src/hooks/useEnhancedConfigs.ts  | 1110 +++++++
 ambari-web/latest/src/hooks/useHostChecks.tsx      |   10 +-
 .../latest/src/hooks/useHostConfigUpdater.ts       |   92 +-
 ambari-web/latest/src/hooks/useKDCSessionState.tsx |   74 +-
 ambari-web/latest/src/hooks/useLazyQuicklinks.ts   | 2025 +++++++++++++
 ambari-web/latest/src/hooks/usePagination.ts       |    1 +
 ambari-web/latest/src/hooks/usePolling.ts          |    5 +-
 ambari-web/latest/src/hooks/usePrevious.ts         |    3 +-
 ambari-web/latest/src/hooks/useServerValidation.ts |  211 ++
 .../latest/src/hooks/useServiceAvailability.ts     |   93 +
 ambari-web/latest/src/hooks/useServiceCache.ts     |   86 +
 ambari-web/latest/src/hooks/useServiceDeletion.tsx | 1949 ++++++++++++
 ambari-web/latest/src/hooks/useStackServices.ts    |    5 +-
 ambari-web/latest/src/hooks/useStackVersion.ts     |    2 +-
 ambari-web/latest/src/hooks/useStepWizard.ts       |    3 +-
 ambari-web/latest/src/hooks/useUpgrade.ts          |    4 +-
 .../latest/src/screens/Alerts/AlertFilters.tsx     |    2 +-
 .../src/screens/Alerts/HostStackVersions.tsx       |    2 +-
 .../ClusterAdmin/StackAndVersions/ListStack.tsx    |    2 +-
 .../ClusterAdmin/StackAndVersions/ListVersion.tsx  |    2 +-
 .../ClusterAdmin/StackAndVersions/Upgrade.tsx      |    2 +-
 .../StackAndVersions/UpgradeHistory.tsx            |    2 +-
 .../latest/src/screens/ClusterWizard/Step0.tsx     |    1 -
 .../latest/src/screens/ClusterWizard/Step1.tsx     |    5 +-
 .../latest/src/screens/ClusterWizard/Step2.tsx     |   16 +-
 .../latest/src/screens/ClusterWizard/Step3.tsx     |   71 +-
 .../latest/src/screens/ClusterWizard/Step4.tsx     |    4 +-
 .../latest/src/screens/ClusterWizard/Step5.tsx     |  127 +
 .../screens/ClusterWizard/Step7/AccountsTab.tsx    |    1 -
 .../screens/ClusterWizard/Step7/CredentialsTab.tsx |    1 -
 .../screens/ClusterWizard/Step7/RestAllTabs.tsx    |   70 +
 .../src/screens/ClusterWizard/Step7/index.tsx      | 2316 +++++++++++++++
 .../latest/src/screens/ClusterWizard/Step8.tsx     |    9 +-
 .../latest/src/screens/ClusterWizard/Step9.tsx     |    6 +-
 .../screens/ClusterWizard/clusterStore/context.tsx |  188 ++
 .../screens/ClusterWizard/clusterStore/reducer.ts  |   43 +
 .../screens/ClusterWizard/clusterStore/types.ts    |   14 +
 .../latest/src/screens/ClusterWizard/constants.ts  |    1 -
 .../ClusterWizard/hooks/useHostComponents.ts       |   75 +
 .../ClusterWizard/hooks/useServiceComponents.ts    |    3 +-
 .../latest/src/screens/ClusterWizard/index.tsx     |    7 +-
 ...ckServiceComponent.ts => AssignMastersTypes.ts} |   58 +-
 .../ClusterWizard/types/StackServiceComponent.ts   |   47 +-
 ...{VersionDefinition.ts => VersionsDefinition.ts} |    0
 .../src/screens/ClusterWizard/types/step7Types.ts  |   17 +
 .../latest/src/screens/ClusterWizard/utils.ts      |    5 +-
 .../src/screens/ClusterWizard/wizardSteps.tsx      |  276 +-
 .../src/screens/CommonConfigs/AdvancedConfigs.tsx  | 1411 +++++++++
 .../screens/CommonConfigs/ChooseConfigGroup.tsx    |  236 ++
 .../latest/src/screens/CommonConfigs/Config.tsx    | 3141 ++++++++++++++++++++
 .../src/screens/CommonConfigs/ConfigUtils.ts       | 1795 +++++++++++
 .../src/screens/CommonConfigs/TestConnection.tsx   |  580 ++++
 .../latest/src/screens/CommonConfigs/index.tsx     |  187 ++
 .../src/screens/CommonConfigs/types/index.ts       |  203 ++
 .../src/screens/Dashboard/DashboardHeatmaps.tsx    |   10 +-
 ambari-web/latest/src/screens/Heatmaps/index.tsx   |   10 +-
 .../AddHostWizard/wizardDataStore/context.tsx      |    2 +-
 .../latest/src/screens/Hosts/HostConfigs.tsx       |  889 ++++++
 ambari-web/latest/src/screens/Hosts/utils.tsx      |    2 +-
 .../src/screens/Kerberos/Kerberos_identitites.ts   |  165 +
 ambari-web/latest/src/store/ServiceContext.tsx     |    9 +
 ambari-web/latest/tsconfig.app.json                |    5 +-
 140 files changed, 28126 insertions(+), 1083 deletions(-)

diff --git a/ambari-web/latest/package.json b/ambari-web/latest/package.json
index 4d1a5418dd..e4379b2021 100755
--- a/ambari-web/latest/package.json
+++ b/ambari-web/latest/package.json
@@ -27,6 +27,7 @@
     "isomorphic-dompurify": "^2.26.0",
     "js-cookie": "^3.0.5",
     "lodash": "^4.17.21",
+    "rc-slider": "^11.1.9",
     "react": "^19.0.0",
     "react-bootstrap": "^2.10.10",
     "react-bootstrap-icons": "^1.11.6",
diff --git a/ambari-web/latest/src/Initializers/AddComponentConfigInitializer.ts b/ambari-web/latest/src/Initializers/AddComponentConfigInitializer.ts
new file mode 100644
index 0000000000..6a5394bfe3
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/AddComponentConfigInitializer.ts
@@ -0,0 +1,556 @@
+/**
+ * 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 HaConfigInitializer from "./HaConfigInitializer";
+import { HostsBasedInitializer } from "./HostsBasedInitializer";
+import ControlFlowInitializer from "./ControlFlowInitializer";
+import UtilitiesForInitialziers from "./UtilitiesForInitialziers.ts";
+
+type ConfigProperty = {
+  name: string;
+  value: string | number;
+  recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+//@ts-ignore
+class AddComponentConfigInitializer extends HaConfigInitializer {
+  protected defaultInitializers: Record<string, any>;
+  protected defaultUniqueInitializers: Record<string, any>;
+  public initializers: Record<string, any>;
+  public uniqueInitializers: Record<string, any>;
+  private __copyInitializers: Record<string, any> = {};
+  private __copyUniqueInitializers: Record<string, any> = {};
+  //@ts-ignore
+  private utilitiesForInitialziers: any;
+
+  constructor() {
+    super();
+
+    this.defaultInitializers = {
+      "zookeeper.connect": this.getHDPStackOnlyHostsPortConfig(
+        "2.2",
+        "ZOOKEEPER_SERVER",
+        "",
+        "",
+        ",",
+        "zkClientPort",
+        true
+      ),
+      "ha.zookeeper.quorum": this.getHDPStackOnlyHostsPortConfig(
+        "2.2",
+        "ZOOKEEPER_SERVER",
+        "",
+        "",
+        ",",
+        "zkClientPort",
+        true
+      ),
+      "hbase.zookeeper.quorum":
+        HostsBasedInitializer.getHostsListComponentConfig(
+          "ZOOKEEPER_SERVER",
+          true
+        ),
+      "instance.zookeeper.host": this.getHostsWithPortConfig(
+        "ZOOKEEPER_SERVER",
+        "",
+        "",
+        ",",
+        "zkClientPort",
+        true
+      ),
+      "templeton.zookeeper.hosts": this.getHostsWithPortConfig(
+        "ZOOKEEPER_SERVER",
+        "",
+        "",
+        ",",
+        "zkClientPort",
+        true
+      ),
+      "hive.cluster.delegation.token.store.zookeeper.connectString":
+        this.getHostsWithPortConfig(
+          "ZOOKEEPER_SERVER",
+          "",
+          "",
+          ",",
+          "zkClientPort",
+          true
+        ),
+      "hive.zookeeper.quorum": this.getHDPStackOnlyHostsPortConfig(
+        "2.2",
+        "ZOOKEEPER_SERVER",
+        "",
+        "",
+        ",",
+        "zkClientPort",
+        true
+      ),
+      "hadoop.registry.zk.quorum": this.getHDPStackOnlyHostsPortConfig(
+        "2.2",
+        "ZOOKEEPER_SERVER",
+        "",
+        "",
+        ",",
+        "zkClientPort",
+        true
+      ),
+      "hadoop.proxyuser.{{hiveUser}}.hosts": this.getComponentsHostsConfig(
+        [
+          "HIVE_SERVER",
+          "WEBHCAT_SERVER",
+          "HIVE_METASTORE",
+          "HIVE_SERVER_INTERACTIVE",
+        ],
+        false,
+        true
+      ),
+      "hive.metastore.uris": this.getHostsWithPortConfig(
+        "HIVE_METASTORE",
+        "thrift://",
+        "",
+        ",thrift://",
+        "hiveMetastorePort",
+        true
+      ),
+    };
+
+    this.defaultUniqueInitializers = {
+      "yarn.resourcemanager.zk-address": this.initYarnRMZkAddress,
+      "templeton.hive.properties": this._initTempletonHiveProperties,
+      "atlas.graph.index.search.solr.zookeeper-url":
+        this._initAtlasGraphIndexSearchSolrZkUrl,
+    };
+
+    this.initializers = {};
+    this.uniqueInitializers = {};
+  }
+
+  setup(): void;
+
+  setup(settings?: Record<string, any>) {
+    if (!settings) {
+      this._updateInitializers();
+    } else {
+      //@ts-ignore
+      this._updateInitializers(settings);
+    }
+  }
+
+  updateSiteObj(
+    siteConfigs: Record<string, any>,
+    configProperty: ConfigProperty
+  ): boolean {
+    if (!siteConfigs || !configProperty) return false;
+
+    const initializer = this.initializers[configProperty.name];
+    const isArray = !!(
+      initializer &&
+      (initializer.type === "json_stringified_value" ||
+        (Array.isArray(initializer) &&
+          initializer.some(
+            (item: any) => item.type === "json_stringified_value"
+          )))
+    );
+
+    UtilitiesForInitialziers.updateHostsListValue(
+      siteConfigs,
+      //@ts-ignore
+      configProperty.filename,
+      configProperty.name,
+      //@ts-ignore
+      configProperty.value,
+      isArray
+    );
+    return true;
+  }
+
+  getNameNodeHAOnlyHostsConfig(components: string[], asArray: boolean): any[] {
+    return [
+      ControlFlowInitializer.getNameNodeHAControl(),
+      //@ts-ignore
+      this.getComponentsHostsConfig(components, asArray),
+    ];
+  }
+
+  // type ComponentsHostsConfig = {
+  //     type: string;
+  //     components: string[];
+  //     asArray: boolean;
+  //     isInstalled?: boolean;
+  // };
+
+  getComponentsHostsConfig(
+    components: string | string[],
+    asArray: boolean = false,
+    isInstalled?: boolean
+  ) {
+    const ret = {
+      type: "hosts_with_components",
+      components: Array.isArray(components) ? components : [components],
+      asArray,
+      isInstalled,
+    };
+    return ret;
+  }
+
+  getHostsWithPortConfig(
+    component: string,
+    prefix: string,
+    suffix: string,
+    delimiter: string,
+    port: string,
+    portFromDependencies: boolean
+  ): {
+    type: string;
+    component: string;
+    modifier: {
+      prefix: string;
+      suffix: string;
+      delimiter: string;
+    };
+    portKey?: string;
+    port?: string;
+    componentExists?: boolean | undefined;
+  } {
+    const ret = HostsBasedInitializer.getHostsWithPortConfig(
+      component,
+      prefix,
+      suffix,
+      delimiter,
+      port,
+      portFromDependencies
+    ) as {
+      type: string;
+      component: string;
+      modifier: {
+        prefix: string;
+        suffix: string;
+        delimiter: string;
+      };
+      portKey?: string;
+      port?: string;
+      componentExists?: boolean;
+    };
+    ret.componentExists = true;
+    return ret;
+  }
+
+  getNameNodeHAOnlyHostsPortConfig(
+    component: string,
+    prefix: string,
+    suffix: string,
+    delimiter: string,
+    port: string,
+    portFromDependencies: boolean
+  ): any[] {
+    return [
+      ControlFlowInitializer.getNameNodeHAControl(),
+      HostsBasedInitializer.getHostsWithPortConfig(
+        component,
+        prefix,
+        suffix,
+        delimiter,
+        port,
+        portFromDependencies
+      ),
+    ];
+  }
+
+  getResourceManagerHAOnlyHostsPortConfig(
+    component: string,
+    prefix: string,
+    suffix: string,
+    delimiter: string,
+    port: string,
+    portFromDependencies: boolean
+  ): any[] {
+    return [
+      ControlFlowInitializer.getResourceManagerHAControl(),
+      this.getHostsWithPortConfig(
+        component,
+        prefix,
+        suffix,
+        delimiter,
+        port,
+        portFromDependencies
+      ),
+    ];
+  }
+
+  getHostsListComponentJSONStringifiedConfig(
+    component: string,
+    componentExists: boolean,
+    //@ts-ignore
+    delimiter: string
+  ): any[] {
+    return [
+      //@ts-ignore
+      this.getHostsListComponentConfig(component, componentExists),
+      //@ts-ignore
+      this.getJSONStringifiedValueConfig(),
+    ];
+  }
+
+  getHDPStackOnlyHostsPortConfig(
+    minStackVersion: string,
+    component: string,
+    prefix: string,
+    suffix: string,
+    delimiter: string,
+    port: string,
+    portFromDependencies: boolean
+  ): any[] {
+    return [
+      ControlFlowInitializer.getHDPStackVersionControl(minStackVersion),
+      this.getHostsWithPortConfig(
+        component,
+        prefix,
+        suffix,
+        delimiter,
+        port,
+        portFromDependencies
+      ),
+    ];
+  }
+
+  cleanup() {
+    this._restoreInitializers();
+  }
+
+  // private _updateInitializers(settings: Record<string, any>): void {
+  //     this.__copyInitializers = { ...this.initializers };
+  //     this.__copyUniqueInitializers = { ...this.uniqueInitializers };
+  //
+  //     this.initializers = this._updateNames(this.initializers, settings);
+  //     this.uniqueInitializers = this._updateNames(this.uniqueInitializers, settings);
+  // }
+
+  private deepCopy(obj: any): any {
+    return JSON.parse(JSON.stringify(obj));
+  }
+
+  // Updates the initializers and uniqueInitializers based on settings
+
+  private _updateInitializers(): void;
+
+  private _updateInitializers(settings?: Record<string, any>) {
+    if (!settings) {
+      this._bootstrapInitializers(Object.keys(this.defaultInitializers));
+    } else {
+      this.__copyInitializers = this.deepCopy(this.defaultInitializers);
+      const updatedInitializers = this._updateNames(
+        "defaultInitializers",
+        settings
+      );
+      this._setForComputed("defaultInitializers", updatedInitializers);
+
+      this.__copyUniqueInitializers = this.deepCopy(
+        this.defaultUniqueInitializers
+      );
+      const updatedUniqueInitializers = this._updateNames(
+        "defaultUniqueInitializers",
+        settings
+      );
+      this._setForComputed(
+        "defaultUniqueInitializers",
+        updatedUniqueInitializers
+      );
+    }
+  }
+
+  // private _restoreInitializers() {
+  //     this.initializers = { ...this.defaultInitializers };
+  //     this.uniqueInitializers = { ...this.defaultUniqueInitializers };
+  // }
+
+  _updateNames(sourceKey: any, settings: any) {
+    settings = settings || {};
+    //@ts-ignore
+    var source = this[sourceKey];
+    let updatedSource: Record<string, any> = {};
+    Object.keys(source).forEach((configName) => {
+      const initializer = source[configName];
+
+      // Use regex to replace any placeholder in the format {{...}} with the settings string
+      const updatedName = configName.replace(/{{.*?}}/g, settings);
+      updatedSource[updatedName] = initializer;
+    });
+    return updatedSource;
+  }
+
+  // Updates the initializers and uniqueInitializers based on settings
+  // public _updateInitializers(settings: Record<string, any> = {}): void {
+  //     this.__copyInitializers = this.deepCopy(this.initializers);
+  //     const updatedInitializers = this._updateNames('initializers', settings);
+  //     console.log("time to set computed properties for default initializers");
+  //     this._setForComputed('initializers', updatedInitializers);
+  //
+  //     this.__copyUniqueInitializers = this.deepCopy(this.uniqueInitializers);
+  //     const updatedUniqueInitializers = this._updateNames('uniqueInitializers', settings);
+  //     this._setForComputed('uniqueInitializers', updatedUniqueInitializers);
+  // }
+
+  // Restores the initializers to their original state
+  public _restoreInitializers(): void {
+    this.__copyInitializers = this.deepCopy(this.defaultInitializers);
+    this.__copyUniqueInitializers = this.deepCopy(
+      this.defaultUniqueInitializers
+    );
+
+    if (this.__copyInitializers) {
+      this._setForComputed(
+        "defaultInitializers",
+        this.deepCopy(this.__copyInitializers)
+      );
+    }
+    if (this.__copyUniqueInitializers) {
+      this._setForComputed(
+        "defaultUniqueInitializers",
+        this.deepCopy(this.__copyUniqueInitializers)
+      );
+    }
+  }
+
+  // Sets a value for a computed property
+  private _setForComputed(key: string, value: any): void {
+    //@ts-ignore
+    this[key] = value;
+  }
+
+  // /**
+  //  * Initializes the Yarn ResourceManager ZooKeeper address.
+  //  * @param configProperty The configuration property to be initialized.
+  //  * @param localDB The local database containing master component hosts.
+  //  * @param dependencies The dependencies containing the ZooKeeper client port.
+  //  * @returns The updated configuration property with the ZooKeeper address.
+  //  */
+  // private _initYarnRMZkAddress(configProperty: ConfigProperty, localDB: LocalDB, dependencies: Dependencies): ConfigProperty {
+  //     const value = localDB.masterComponentHosts
+  //         .filter((host: any) => host.component === 'ZOOKEEPER_SERVER' && host.isInstalled)
+  //         .map((host: any) => `${host.hostName}:${dependencies.zkClientPort}`)
+  //         .join(',');
+  //
+  //     configProperty.value = value;
+  //     configProperty.recommendedValue = value;
+  //
+  //     return configProperty;
+  // }
+
+  private initYarnRMZkAddress(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    //@ts-ignore
+    return HostsBasedInitializer._initAsHostsWithPort(
+      //@ts-ignore
+      configProperty,
+      localDB,
+      dependencies,
+      {
+        component: "ZOOKEEPER_SERVER",
+        componentExists: true,
+        modifier: {
+          prefix: "",
+          suffix: "",
+          delimiter: ",",
+        },
+        portKey: "zkClientPort",
+      }
+    );
+  }
+
+  private _initTempletonHiveProperties(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ) {
+    const hostNames = localDB.masterComponentHosts
+      .filter(
+        (host: any) => host.component === "HIVE_METASTORE" && host.isInstalled
+      )
+      .map(
+        (host: any) =>
+          `thrift://${host.hostName}:${dependencies.hiveMetastorePort}`
+      )
+      .join(",");
+    configProperty.value = hostNames;
+    configProperty.recommendedValue = hostNames;
+    return configProperty;
+  }
+
+  private _initAtlasGraphIndexSearchSolrZkUrl(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ) {
+    const solr = dependencies.infraSolrZnode;
+    const hostNames = localDB.masterComponentHosts
+      .filter(
+        (host: any) => host.component === "ZOOKEEPER_SERVER" && host.isInstalled
+      )
+      .map(
+        (host: any) => `${host.hostName}:${dependencies.zkClientPort}${solr}`
+      )
+      .join(",");
+    configProperty.value = hostNames;
+    configProperty.recommendedValue = hostNames;
+    return configProperty;
+  }
+
+  //@ts-ignore
+  private _bootstrapInitializers(properties: string[] | null) {
+    const initializers: Record<string, any> = {};
+    const uniqueInitializers: Record<string, any> = {};
+    const defaultInitializers = this.defaultInitializers;
+    const defaultUniqueInitializers = this.defaultUniqueInitializers;
+
+    if (!properties) {
+      this.initializers = { ...defaultInitializers };
+      this.uniqueInitializers = { ...defaultUniqueInitializers };
+    } else {
+      properties.forEach((propertyName) => {
+        if (defaultInitializers[propertyName]) {
+          initializers[propertyName] = defaultInitializers[propertyName];
+        } else if (defaultUniqueInitializers[propertyName]) {
+          uniqueInitializers[propertyName] =
+            defaultUniqueInitializers[propertyName];
+        }
+      });
+      this.initializers = initializers;
+      this.uniqueInitializers = uniqueInitializers;
+    }
+  }
+}
+//@ts-ignore
+// Apply mixins
+interface AddComponentConfigInitializer
+  extends HostsBasedInitializer,
+    ControlFlowInitializer {}
+Object.assign(
+  AddComponentConfigInitializer.prototype,
+  HostsBasedInitializer.prototype
+);
+Object.assign(
+  AddComponentConfigInitializer.prototype,
+  ControlFlowInitializer.prototype
+);
+
+export default AddComponentConfigInitializer;
diff --git a/ambari-web/latest/src/hooks/useKDCSessionState.tsx b/ambari-web/latest/src/Initializers/AddHiveComponentsInitializer.ts
similarity index 51%
copy from ambari-web/latest/src/hooks/useKDCSessionState.tsx
copy to ambari-web/latest/src/Initializers/AddHiveComponentsInitializer.ts
index a57a7b8faa..78f502e03d 100644
--- a/ambari-web/latest/src/hooks/useKDCSessionState.tsx
+++ b/ambari-web/latest/src/Initializers/AddHiveComponentsInitializer.ts
@@ -16,14 +16,27 @@
  * limitations under the License.
  */
 
-//TODO: This will be implemented soon to fetch KDC session state
+import AddComponentConfigInitializer from "./AddComponentConfigInitializer.ts";
 
-function useKDCSessionState(_cancelHandler: Function) {
-  const getKDCSessionState = async (callback: Function) => {
-    callback();
-  };
+class AddHiveComponentsInitializer extends AddComponentConfigInitializer {
+  //@ts-ignore
+  private initializeForProperties: string[];
 
-  return { getKDCSessionState };
+  constructor() {
+    super();
+    this.initializeForProperties = [
+      "hive.metastore.uris",
+      "templeton.hive.properties",
+      "hadoop.proxyuser.{{hiveUser}}.hosts",
+    ];
+
+    this.defaultInitializers = Object.keys(this.defaultInitializers)
+      .filter((key) => this.initializeForProperties.includes(key))
+      .reduce((filteredInitializers, key) => {
+        filteredInitializers[key] = this.defaultInitializers[key];
+        return filteredInitializers;
+      }, {} as Record<string, any>);
+  }
 }
 
-export default useKDCSessionState;
+export default AddHiveComponentsInitializer;
diff --git a/ambari-web/latest/src/Initializers/AddZooKeeperComponentsInitializer.ts b/ambari-web/latest/src/Initializers/AddZooKeeperComponentsInitializer.ts
new file mode 100644
index 0000000000..510c190ff5
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/AddZooKeeperComponentsInitializer.ts
@@ -0,0 +1,58 @@
+/**
+ * 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 AddComponentConfigInitializer from "./AddComponentConfigInitializer.ts";
+class AddZooKeeperComponentsInitializer extends AddComponentConfigInitializer {
+    //@ts-ignore
+    private initializeForProperties: any;
+    constructor() {
+        super();
+        //@ts-ignore
+        this.initializeForProperties = [
+            'zookeeper.connect',
+            'ha.zookeeper.quorum',
+            'hbase.zookeeper.quorum',
+            'instance.zookeeper.host',
+            'templeton.zookeeper.hosts',
+            'hive.cluster.delegation.token.store.zookeeper.connectString',
+            'yarn.resourcemanager.zk-address',
+            'hive.zookeeper.quorum',
+            'storm.zookeeper.servers',
+            'hadoop.registry.zk.quorum',
+            'atlas.audit.hbase.zookeeper.quorum',
+            'atlas.graph.index.search.solr.zookeeper-url',
+            'atlas.graph.storage.hostname',
+            'atlas.kafka.zookeeper.connect'
+        ]
+        this.defaultInitializers = Object.keys(this.defaultInitializers)
+            .filter((key) => this.initializeForProperties.includes(key))
+            .reduce((filteredInitializers, key) => {
+                filteredInitializers[key] = this.defaultInitializers[key];
+                return filteredInitializers;
+            }, {} as Record<string, any>);
+
+        this.defaultUniqueInitializers = Object.keys(this.defaultUniqueInitializers)
+            .filter((key) => this.initializeForProperties.includes(key))
+            .reduce((filteredInitializers, key) => {
+                filteredInitializers[key] = this.defaultUniqueInitializers[key];
+                return filteredInitializers;
+            }, {} as Record<string, any>);
+    }
+}
+
+export default AddZooKeeperComponentsInitializer;
diff --git a/ambari-web/latest/src/Initializers/ConfigInitializer.ts b/ambari-web/latest/src/Initializers/ConfigInitializer.ts
new file mode 100644
index 0000000000..6ffa620f5f
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/ConfigInitializer.ts
@@ -0,0 +1,128 @@
+/**
+ * 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 { HostsBasedInitializer } from "./HostsBasedInitializer.ts";
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+type InitializerType = {
+    name: string;
+    method: string;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+class ConfigInitializer extends HostsBasedInitializer {
+    constructor() {
+        super(); // Call the superclass constructor
+        this.initializerTypes = [
+            // ...super.initializerTypes, // Include initializerTypes from the superclass
+            { name: "host_with_port", method: "_initAsHostWithPort" },
+            { name: "hosts_with_port", method: "_initAsHostsWithPort" },
+            { name: "host_with_component", method: "_initAsHostWithComponent" },
+            { name: "hosts_with_components", method: "_initAsHostsWithComponents" },
+            {
+                name: "hosts_list_with_component",
+                method: "_initAsHostsListWithComponent",
+            },
+        ];
+    }
+
+    private _initializerFlowCode = {
+        next: 0,
+        skipNext: 1,
+        skipAll: 2,
+    };
+
+    private defaultInitializers: Record<string, any> = {};
+    private defaultUniqueInitializers: Record<string, any> = {};
+    public initializerTypes: InitializerType[] = [];
+
+    public flowNext(): number {
+        return this._initializerFlowCode.next;
+    }
+
+    public flowSkipNext(): number {
+        return this._initializerFlowCode.skipNext;
+    }
+
+    public flowSkipAll(): number {
+        return this._initializerFlowCode.skipAll;
+    }
+
+    public initialValue(
+        configProperty: ConfigProperty,
+        localDB: LocalDB,
+        dependencies: Dependencies
+    ): ConfigProperty {
+        const configName = configProperty.name;
+        const initializer = this.defaultInitializers[configName];
+
+        if (initializer) {
+            return this._defaultInitializer(configProperty, localDB, dependencies);
+        }
+
+        const uniqueInitializer = this.defaultUniqueInitializers[configName];
+        if (uniqueInitializer) {
+            uniqueInitializer(configProperty, localDB, dependencies);
+        }
+
+        configProperty.recommendedValue = configProperty.value;
+        return configProperty;
+    }
+
+    private _defaultInitializer(
+        configProperty: ConfigProperty,
+        localDB: LocalDB,
+        dependencies: Dependencies
+    ): ConfigProperty {
+        const initializer = this.defaultInitializers[configProperty.name];
+        if (initializer) {
+            const initializerArray = Array.isArray(initializer)
+                ? initializer
+                : [initializer];
+            for (const init of initializerArray) {
+                const initializerType = this.initializerTypes.find(
+                    (type) => type.name === init.type
+                );
+                if (initializerType) {
+                    const method = HostsBasedInitializer[
+                        initializerType.method as keyof typeof HostsBasedInitializer
+                        ] as any;
+                    if (typeof method === "function") {
+                        configProperty = method(
+                            configProperty,
+                            localDB,
+                            dependencies,
+                            init
+                        );
+                    }
+                }
+            }
+        }
+        return configProperty;
+    }
+}
+
+export default ConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/ControlFlowInitializer.ts b/ambari-web/latest/src/Initializers/ControlFlowInitializer.ts
new file mode 100644
index 0000000000..cc37aec919
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/ControlFlowInitializer.ts
@@ -0,0 +1,136 @@
+/**
+ * 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.
+ */
+
+type ConfigProperty = {
+    value: string | number;
+    recommendedValue?: string | number;
+};
+
+type TopologyLocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+type Initializer = {
+    type: string;
+    isChecker: boolean;
+    stackVersion?: string;
+};
+
+class ControlFlowInitializer {
+    //@ts-ignore
+    private initializerTypes = [
+        { name: "namenode_ha_enabled", method: "_initNameNodeHACheck" },
+        {
+            name: "resourcemanager_ha_enabled",
+            method: "_initResourceManagerHACheck",
+        },
+        { name: "hdp_stack_version_checker", method: "_initHDPStackVersionCheck" },
+    ];
+
+    public static getHDPStackVersionControl(
+        minStackVersionNumber: string
+    ): Initializer {
+        return {
+            type: "hdp_stack_version_checker",
+            isChecker: true,
+            stackVersion: minStackVersionNumber,
+        };
+    }
+
+    //@ts-ignore
+    private _initHDPStackVersionCheck(
+        //@ts-ignore
+        configProperty: ConfigProperty,
+        //@ts-ignore
+        localDB: TopologyLocalDB,
+        //@ts-ignore
+        dependencies: Dependencies,
+        initializer: Initializer
+    ): number {
+        return this.compareVersions(
+            this.getCurrentStackVersion(),
+            initializer.stackVersion || ""
+        ) > -1
+            ? this.flowNext()
+            : this.flowSkipAll();
+    }
+
+    public static getNameNodeHAControl(): Initializer {
+        return { type: "namenode_ha_enabled", isChecker: true };
+    }
+
+    //@ts-ignore
+    private _initNameNodeHACheck(
+        //@ts-ignore
+        configProperty: ConfigProperty,
+        //@ts-ignore
+        localDB: TopologyLocalDB,
+        //@ts-ignore
+        dependencies: Dependencies
+    ): number {
+        return this.isHaEnabled() ? this.flowNext() : this.flowSkipNext();
+    }
+
+    public static getResourceManagerHAControl(): Initializer {
+        return { type: "resourcemanager_ha_enabled", isChecker: true };
+    }
+
+    //@ts-ignore
+    private _initResourceManagerHACheck(
+        //@ts-ignore
+        configProperty: ConfigProperty,
+        //@ts-ignore
+        localDB: TopologyLocalDB,
+        //@ts-ignore
+        dependencies: Dependencies
+    ): number {
+        return this.isRMHaEnabled() ? this.flowNext() : this.flowSkipNext();
+    }
+
+    private flowNext(): number {
+        return 0; // Represents "next"
+    }
+
+    private flowSkipNext(): number {
+        return 1; // Represents "skipNext"
+    }
+
+    private flowSkipAll(): number {
+        return 2; // Represents "skipAll"
+    }
+
+    private compareVersions(version1: string, version2: string): number {
+        // Add logic to compare versions
+        return version1.localeCompare(version2, undefined, { numeric: true });
+    }
+
+    private getCurrentStackVersion(): string {
+        // Replace with logic to get the current stack version
+        return "3.0.0";
+    }
+
+    private isHaEnabled(): boolean {
+        // Replace with logic to check if HA is enabled
+        return true;
+    }
+
+    private isRMHaEnabled(): boolean {
+        // Replace with logic to check if ResourceManager HA is enabled
+        return true;
+    }
+}
+
+export default ControlFlowInitializer;
\ No newline at end of file
diff --git a/ambari-web/latest/src/screens/ClusterWizard/types/StackServiceComponent.ts b/ambari-web/latest/src/Initializers/HaConfigInitializer.ts
similarity index 63%
copy from ambari-web/latest/src/screens/ClusterWizard/types/StackServiceComponent.ts
copy to ambari-web/latest/src/Initializers/HaConfigInitializer.ts
index 2f0142ca5a..cdcd886644 100644
--- a/ambari-web/latest/src/screens/ClusterWizard/types/StackServiceComponent.ts
+++ b/ambari-web/latest/src/Initializers/HaConfigInitializer.ts
@@ -16,27 +16,18 @@
  * limitations under the License.
  */
 
-export interface StackServiceComponent {
-  componentName: string;
-  isDisabled: boolean;
-}
-
-export interface ServiceComponent {
-  StackServiceComponents: StackServiceComponent;
-}
+import ConfigInitializer from "./ConfigInitializer";
+//@ts-ignore
+import NnHaConfigInitializer from "../Utils/configs.ts";
 
-export interface Service {
-  StackServices: {
-    service_name: string;
-  };
-  components: ServiceComponent[];
+class HaConfigInitializer extends ConfigInitializer {
+    constructor() {
+        super();
+        // this.initializerTypes = [
+        //     { name: "host_with_port", method: "_initAsHostWithPort" },
+        //     { name: "hosts_with_port", method: "_initAsHostsWithPort" },
+        // ];
+    }
 }
 
-export interface ServicesResponse {
-  items: Service[];
-}
-
-export interface SelectedService {
-  is_selected: boolean;
-  service_name: string;
-}
+export default HaConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/HostsBasedInitializer.ts b/ambari-web/latest/src/Initializers/HostsBasedInitializer.ts
new file mode 100644
index 0000000000..1d5f9a6604
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/HostsBasedInitializer.ts
@@ -0,0 +1,331 @@
+/**
+ * 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 {ExtendedTopologyLocalDB, NnHaConfigDependencies} from "../Utils/configs.ts";
+
+type ConfigProperty = {
+  value: string;
+  recommendedValue: string;
+};
+
+type TopologyLocalDB = {
+  masterComponentHosts: {
+    component: string;
+    hostName: string;
+    isInstalled?: boolean;
+  }[];
+};
+
+type Initializer = {
+  component: string | string[];
+  componentExists?: boolean;
+  modifier?: {
+    prefix?: string;
+    suffix?: string;
+    delimiter?: string;
+    regex?: string;
+  };
+  asArray?: boolean;
+  components?: string[];
+  portKey?: string;
+  port?: string;
+};
+
+type Dependencies = Record<string, string | number>;
+
+export class HostsBasedInitializer {
+  static _initAsHostWithPort(
+    configProperty: ConfigProperty,
+    localDB: TopologyLocalDB,
+    dependencies: Dependencies,
+    initializer: Initializer
+  ): ConfigProperty {
+    const host = localDB.masterComponentHosts
+      .filter((host) => host.component === initializer.component)
+      .find((host) => host.isInstalled === initializer.componentExists);
+
+    const hostName = host?.hostName || "";
+    const port = HostsBasedInitializer.__getPort(dependencies, initializer);
+    const value =
+      (initializer.modifier?.prefix || "") +
+      hostName +
+      (port ? `:${port}` : "") +
+      (initializer.modifier?.suffix || "");
+
+    configProperty.value = value;
+    configProperty.recommendedValue = value;
+
+    return configProperty;
+  }
+
+  static getComponentsHostsConfig(
+    components: string | string[],
+    asArray: boolean = false,
+    isInstalled?: boolean
+  ) {
+    return {
+      type: "hosts_with_components",
+      components: Array.isArray(components) ? components : [components],
+      asArray,
+      isInstalled,
+    };
+  }
+
+  static getSimpleComponentConfig(
+    component: string,
+    withModifier: boolean = true
+  ) {
+    const config: any = {
+      type: "host_with_component",
+      component,
+    };
+    if (withModifier) {
+      config.modifier = {
+        type: "regexp",
+        regex: "([\\w|\\.]*)(?=:)",
+      };
+    }
+    return config;
+  }
+
+  static getComponentConfigWithAffixes(
+    component: string,
+    prefix: string = "",
+    suffix: string = ""
+  ) {
+    return {
+      type: "host_with_component",
+      component,
+      modifier: {
+        type: "regexp",
+        regex: ":\\/\\/([\\w|\\.]*)(?=:)",
+        prefix,
+        suffix,
+      },
+    };
+  }
+
+  static getHostWithPortConfig(
+    component: string,
+    componentExists: boolean,
+    prefix: string = "",
+    suffix: string = "",
+    port: string,
+    portFromDependencies: boolean = false
+  ) {
+    const config: any = {
+      type: "host_with_port",
+      component,
+      componentExists,
+      modifier: {
+        prefix,
+        suffix,
+      },
+    };
+    if (portFromDependencies) {
+      config.portKey = port;
+    } else {
+      config.port = port;
+    }
+    return config;
+  }
+
+  static getHostsWithPortConfig(
+    component: string,
+    prefix: string = "",
+    suffix: string = "",
+    delimiter: string = ",",
+    port: string,
+    portFromDependencies: boolean = false
+  ): {
+    type: string;
+    component: string;
+    modifier: {
+      prefix: string;
+      suffix: string;
+      delimiter: string;
+    };
+    portKey?: string;
+    port?: string;
+    componentExists?: boolean | undefined;
+  } {
+    const ret: {
+      type: string;
+      component: string;
+      modifier: {
+        prefix: string;
+        suffix: string;
+        delimiter: string;
+      };
+      portKey?: string;
+      port?: string;
+      componentExists?: boolean | undefined;
+    } = {
+      type: "hosts_with_port",
+      component,
+      modifier: {
+        prefix: prefix || "",
+        suffix: suffix || "",
+        delimiter: delimiter || ",",
+      },
+    };
+
+    if (portFromDependencies) {
+      ret.portKey = port;
+    } else {
+      ret.port = port;
+    }
+
+    return ret;
+  }
+
+  static _initAsHostWithComponent(
+    configProperty: ConfigProperty,
+    localDB: TopologyLocalDB,
+    //@ts-ignore
+    dependencies: Dependencies,
+    initializer: Initializer
+  ): ConfigProperty {
+    const component = localDB.masterComponentHosts.find(
+      (host) => host.component === initializer.component
+    );
+    if (!component) {
+      return configProperty;
+    }
+    if (initializer.modifier) {
+      const replaceWith =
+        (initializer.modifier.prefix || "") +
+        component.hostName +
+        (initializer.modifier.suffix || "");
+      configProperty.value = replaceWith;
+      configProperty.recommendedValue = replaceWith;
+    } else {
+      configProperty.value = component.hostName;
+      configProperty.recommendedValue = component.hostName;
+    }
+    return configProperty;
+  }
+
+  static _initAsHostsWithComponents(
+    configProperty: ConfigProperty,
+    localDB: TopologyLocalDB,
+    //@ts-ignore
+    dependencies: Dependencies,
+    initializer: Initializer
+  ): ConfigProperty {
+    // const hostNames = localDB.masterComponentHosts
+    //     .filter((host) => initializer.components?.includes(host.component))
+    //     //@ts-ignore
+    //     .filter((host) => initializer.isInstalled === undefined || host.isInstalled === initializer.isInstalled)
+    //     .map((host) => host.hostName)
+    //     .sort();
+
+    const hostNames = Array.from(
+      new Set(
+        localDB.masterComponentHosts
+          .filter((host) => initializer.components?.includes(host.component))
+          //@ts-ignore
+          .filter(
+            (host) =>
+              //@ts-ignore
+              initializer.isInstalled === undefined ||
+              //@ts-ignore
+              host.isInstalled === initializer.isInstalled
+          )
+          .map((host) => host.hostName)
+      )
+    ).sort();
+
+    const value = initializer.asArray ? hostNames : hostNames.join(",");
+    //@ts-ignore
+    configProperty.value = value;
+    //@ts-ignore
+    configProperty.recommendedValue = value;
+    return configProperty;
+  }
+
+  static _initAsHostsWithPort(
+    configProperty: ConfigProperty,
+    localDB: TopologyLocalDB,
+    dependencies: Dependencies,
+    initializer: Initializer
+  ): ConfigProperty {
+    const hostNames = localDB.masterComponentHosts
+      .filter((host) => host.component === initializer.component)
+      .filter(
+        (host) =>
+          initializer.componentExists === undefined ||
+          host.isInstalled === initializer.componentExists
+      )
+      .map((host) => host.hostName);
+
+    const port = HostsBasedInitializer.__getPort(dependencies, initializer);
+    const value =
+      (initializer.modifier?.prefix || "") +
+      hostNames
+        .map((hostName) => `${hostName}${port ? `:${port}` : ""}`)
+        .join(initializer.modifier?.delimiter || ",") +
+      (initializer.modifier?.suffix || "");
+
+    configProperty.value = value;
+    configProperty.recommendedValue = value;
+    return configProperty;
+  }
+
+  //@ts-ignore
+  static _initAsHostsListWithComponent(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies, initializer: any): ConfigProperty {
+    const hostNames = localDB.masterComponentHosts
+        .filter(host => host.component === initializer.component && host.isInstalled === initializer.componentExists)
+        .map(host => host.hostName)
+        .join(initializer.modifier.delimiter);
+    config.value = hostNames;
+    config.recommendedValue = hostNames;
+    return config;
+  }
+
+  static getHostsListComponentConfig(
+    component: string,
+    componentExists: boolean,
+    delimiter?: string
+  ): {
+    type: string;
+    component: string;
+    componentExists: boolean;
+    modifier: {
+      delimiter: string;
+    };
+  } {
+    return {
+      type: "hosts_list_with_component",
+      component: component,
+      componentExists: componentExists,
+      modifier: {
+        delimiter: delimiter == null ? "," : delimiter, // Check for null or undefined
+      },
+    };
+  }
+
+  static __getPort(
+    dependencies: Dependencies,
+    initializer: Initializer
+  ): string | number | undefined {
+    return initializer.portKey
+      ? dependencies[initializer.portKey]
+      : initializer.port;
+  }
+}
diff --git a/ambari-web/latest/src/Initializers/MoveComponentConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveComponentConfigInitializer.ts
new file mode 100644
index 0000000000..756635ea89
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveComponentConfigInitializer.ts
@@ -0,0 +1,259 @@
+/**
+ * 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 ConfigInitializer from './ConfigInitializer';
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+export interface ReassignComponentDependencies {
+  targetHostName: string;
+  sourceHostName: string;
+  namespaceId?: string;
+  [key: string]: any;
+}
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+export interface MoveInitializer {
+  type: string;
+  component?: string;
+  port?: string | number;
+}
+
+/**
+ * Basic class for all Initializers used for configs which are affected by some component's moving from
+ * one host to another
+ */
+export class MoveComponentConfigInitializer extends ConfigInitializer {
+  protected initializers: Record<string, MoveInitializer | MoveInitializer[]> = {};
+  protected uniqueInitializers: Record<string, string> = {};
+  private __copyInitializers?: Record<string, MoveInitializer | MoveInitializer[]>;
+  private __copyUniqueInitializers?: Record<string, string>;
+
+  constructor() {
+    super();
+    this.initializerTypes = [
+      ...this.initializerTypes,
+      { name: 'hosts_with_component', method: '_initAsHostsWithComponentConsideringMoving' },
+      { name: 'target_host', method: '_initAsTargetHost' }
+    ];
+  }
+
+  /**
+   * Setup method to update initializers with settings
+   */
+  public setup(settings: any): void {
+    this._updateInitializers(settings);
+  }
+
+  /**
+   * Cleanup method to restore initializers
+   */
+  public cleanup(): void {
+    this._restoreInitializers();
+  }
+
+  /**
+   * Get initial value for a config property
+   */
+  public initialValue(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const configName = configProperty.name;
+    const initializer = this.initializers[configName];
+
+    if (initializer) {
+      return this._moveDefaultInitializer(configProperty, localDB, dependencies);
+    }
+
+    const uniqueInitializerMethod = this.uniqueInitializers[configName];
+    if (uniqueInitializerMethod && typeof (this as any)[uniqueInitializerMethod] === 'function') {
+      return (this as any)[uniqueInitializerMethod](configProperty, localDB, dependencies);
+    }
+
+    configProperty.recommendedValue = configProperty.value;
+    return configProperty;
+  }
+
+  /**
+   * Initializer for configs with value equal to the hostName where component will be moved (with port)
+   */
+  protected _initAsTargetHost(
+    configProperty: ConfigProperty,
+    _localDB: LocalDB,
+    dependencies: Dependencies,
+    initializer: MoveInitializer
+  ): ConfigProperty {
+    const hostName = dependencies.targetHostName;
+    const port = initializer.port || '';
+    const value = `${hostName}${port ? ':' + port : ''}`;
+    
+    configProperty.value = value;
+    configProperty.recommendedValue = value;
+    return configProperty;
+  }
+
+  /**
+   * Initializer for configs with value equal to the hosts list where needed component exists
+   * Value considers component-moving, so targetHostName will be added to the list
+   * and sourceHostName will be removed
+   */
+  protected _initAsHostsWithComponentConsideringMoving(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies,
+    initializer: MoveInitializer
+  ): ConfigProperty {
+    if (!initializer.component) {
+      return configProperty;
+    }
+
+    let hosts = localDB.masterComponentHosts
+      .filter((host: any) => host.component === initializer.component)
+      .map((host: any) => host.hostName);
+
+    // Remove source host and add target host
+    hosts = hosts.filter((host: string) => host !== dependencies.sourceHostName);
+    if (!hosts.includes(dependencies.targetHostName)) {
+      hosts.push(dependencies.targetHostName);
+    }
+
+    const uniqueHosts = Array.from(new Set(hosts));
+    const value = uniqueHosts.sort().join(',');
+    configProperty.value = value;
+    configProperty.recommendedValue = value;
+    return configProperty;
+  }
+
+  /**
+   * Default initializer that processes the initializer configuration
+   */
+  private _moveDefaultInitializer(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const initializer = this.initializers[configProperty.name];
+    if (initializer) {
+      const initializerArray = Array.isArray(initializer) ? initializer : [initializer];
+      
+      for (const init of initializerArray) {
+        const initializerType = this.initializerTypes.find(type => type.name === init.type);
+        if (initializerType) {
+          const method = (this as any)[initializerType.method];
+          if (typeof method === 'function') {
+            configProperty = method.call(this, configProperty, localDB, dependencies, init);
+          }
+        }
+      }
+    }
+    return configProperty;
+  }
+
+  /**
+   * Setup initializers with settings to replace placeholders like {{namespaceId}}, {{suffix}}
+   * This allows config names with dynamic parts to be resolved at runtime
+   * 
+   * Example:
+   * - Original: 'dfs.namenode.http-address.{{namespaceId}}.{{suffix}}'
+   * - With settings {namespaceId: 'mycluster', suffix: 'nn1'}
+   * - Becomes: 'dfs.namenode.http-address.mycluster.nn1'
+   */
+  private _updateInitializers(settings: any): void {
+    settings = settings || {};
+    
+    // Backup original initializers
+    this.__copyInitializers = JSON.parse(JSON.stringify(this.initializers));
+    this.__copyUniqueInitializers = JSON.parse(JSON.stringify(this.uniqueInitializers));
+    
+    // Update initializers with placeholder replacement
+    this.initializers = this._updateNames(this.initializers, settings);
+    this.uniqueInitializers = this._updateNames(this.uniqueInitializers, settings);
+  }
+
+  /**
+   * Restore initializers to their original state before placeholder replacement
+   */
+  private _restoreInitializers(): void {
+    if (this.__copyInitializers) {
+      this.initializers = JSON.parse(JSON.stringify(this.__copyInitializers));
+      this.__copyInitializers = undefined;
+    }
+    if (this.__copyUniqueInitializers) {
+      this.uniqueInitializers = JSON.parse(JSON.stringify(this.__copyUniqueInitializers));
+      this.__copyUniqueInitializers = undefined;
+    }
+  }
+
+  /**
+   * Replace placeholders in object keys with actual values from settings
+   * 
+   * @param source - Object with keys that may contain placeholders
+   * @param settings - Object with replacement values
+   * @returns Updated object with placeholders replaced
+   */
+  private _updateNames<T>(source: Record<string, T>, settings: any): Record<string, T> {
+    settings = settings || {};
+    const result: Record<string, T> = {};
+    
+    Object.keys(source).forEach(configName => {
+      const initializer = source[configName];
+      let updatedConfigName = configName;
+      
+      // Replace each placeholder with its value from settings
+      Object.keys(settings).forEach(key => {
+        const replaceWith = String(settings[key]);
+        const toReplace = `{{${key}}}`;
+        updatedConfigName = updatedConfigName.replace(new RegExp(toReplace.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), replaceWith);
+      });
+      
+      result[updatedConfigName] = initializer;
+    });
+    return result;
+  }
+
+  /**
+   * Static method to get target host config
+   */
+  public static getTargetHostConfig(port?: string | number): MoveInitializer {
+    return {
+      type: 'target_host',
+      port: port || ''
+    };
+  }
+
+  /**
+   * Static method to get hosts with component config
+   */
+  public static getHostsWithComponentConfig(component: string): MoveInitializer {
+    return {
+      type: 'hosts_with_component',
+      component: component
+    };
+  }
+}
+
+export default MoveComponentConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/MoveHiveComponentConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveHiveComponentConfigInitializer.ts
new file mode 100644
index 0000000000..57f109f993
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveHiveComponentConfigInitializer.ts
@@ -0,0 +1,99 @@
+/**
+ * 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 { MoveComponentConfigInitializer, MoveInitializer } from './MoveComponentConfigInitializer';
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+export interface HiveComponentInitializer extends MoveInitializer {
+  components: string[];
+  movedComponent: string;
+}
+
+/**
+ * Common class for Initializers which are used when some HIVE's component is moved from one host to another
+ */
+export class MoveHiveComponentConfigInitializer extends MoveComponentConfigInitializer {
+  constructor() {
+    super();
+    this.initializerTypes = [
+      ...this.initializerTypes,
+      { name: 'hive_hosts_with_components', method: '_initAsHostsWithComponentsConsideringMovedComponent' }
+    ];
+  }
+
+  /**
+   * Initializer for configs with value equal to the list of hosts where some components exist
+   * This list is affected by component's moving.
+   * Example: movedComponent is 'Component1', list of needed components is ['Component1', 'Component2']
+   * So, when hosts for each needed component will be mapped, host where 'Component1' was before moving ('host1') will be skipped
+   * and host where 'Component1' is moved will be added ('host2')
+   * But, if 'Component2' exists of the 'host1', 'host1' will be added to the hosts list
+   */
+  protected _initAsHostsWithComponentsConsideringMovedComponent(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies,
+    initializer: HiveComponentInitializer
+  ): ConfigProperty {
+    let allHosts: string[] = [];
+    
+    initializer.components.forEach(component => {
+      let hosts = localDB.masterComponentHosts
+        .filter((host: any) => host.component === component)
+        .map((host: any) => host.hostName);
+      
+      if (component === initializer.movedComponent) {
+        hosts = hosts.filter((host: string) => host !== dependencies.sourceHostName);
+        if (!hosts.includes(dependencies.targetHostName)) {
+          hosts.push(dependencies.targetHostName);
+        }
+      }
+      allHosts = allHosts.concat(hosts);
+    });
+
+    const uniqueHosts = Array.from(new Set(allHosts));
+    const value = uniqueHosts.sort().join(',');
+    configProperty.value = value;
+    configProperty.recommendedValue = value;
+    return configProperty;
+  }
+
+  /**
+   * Settings for hive_hosts_with_components-initializer
+   * Used for configs with value equal to the hosts list where needed components exist.
+   * This list is affected by component's moving
+   */
+  public static getHostsWithComponentsConfig(neededComponents: string | string[], movedComponent: string): HiveComponentInitializer {
+    return {
+      type: 'hive_hosts_with_components',
+      components: Array.isArray(neededComponents) ? neededComponents : [neededComponents],
+      movedComponent: movedComponent
+    };
+  }
+}
+
+export default MoveHiveComponentConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/MoveHmConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveHmConfigInitializer.ts
new file mode 100644
index 0000000000..a9fb4d2e00
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveHmConfigInitializer.ts
@@ -0,0 +1,143 @@
+/**
+ * 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 { MoveHiveComponentConfigInitializer } from './MoveHiveComponentConfigInitializer';
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+/**
+ * Initializer for configs which should be affected when Hive Metastore is moved from one host to another
+ */
+export class MoveHmConfigInitializer extends MoveHiveComponentConfigInitializer {
+  private static instance: MoveHmConfigInitializer;
+
+  constructor() {
+    super();
+    
+    this.initializers = {
+      'hadoop.proxyuser.{{hiveUser}}.hosts': MoveHiveComponentConfigInitializer.getHostsWithComponentsConfig(
+        ['HIVE_SERVER', 'HIVE_METASTORE', 'HIVE_SERVER_INTERACTIVE'], 
+        'HIVE_METASTORE'
+      )
+    };
+
+    this.uniqueInitializers = {
+      'hive.metastore.uris': '_initHiveMetastoreUris',
+      'templeton.hive.properties': '_initTempletonHiveProperties'
+    };
+  }
+
+  /**
+   * Unique initializer for hive.metastore.uris-config
+   * Value example: 'thrift://host1:1234,thrift://host2:1234,thrift://host3:1234'
+   */
+  protected _initHiveMetastoreUris(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const hiveMSHosts = this._getHmHostsConsideringMoved(localDB, dependencies);
+    const value = String(configProperty.value);
+
+    // Extract port from existing value
+    const portMatch = value.match(/:[0-9]{2,4}/);
+    const port = portMatch ? portMatch[0].slice(1) : '9083';
+
+    const newValue = hiveMSHosts
+      .filter((host, index, arr) => arr.indexOf(host) === index) // unique hosts
+      .map(hiveMSHost => `thrift://${hiveMSHost}:${port}`)
+      .join(',');
+
+    configProperty.value = newValue;
+    configProperty.recommendedValue = newValue;
+    return configProperty;
+  }
+
+  /**
+   * Unique initializer for templeton.hive.properties-config
+   * Replace existing hosts with new
+   * Value example: 'hive.metastore.local=false,hive.metastore.uris=thrift://host1:9083,hive.metastore.sasl.enabled=false,hive.metastore.execute.setugi=true'
+   */
+  protected _initTempletonHiveProperties(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const hiveMSHosts = this._getHmHostsConsideringMoved(localDB, dependencies);
+    let value = String(configProperty.value);
+    
+    // Replace the thrift URIs in the properties string
+    const hostsString = hiveMSHosts.join('\\,');
+    value = value.replace(/thrift.+[0-9]{2,},/i, `${hostsString},`);
+
+    configProperty.value = value;
+    configProperty.recommendedValue = value;
+    return configProperty;
+  }
+
+  /**
+   * Get list of hosts where HIVE_METASTORE exists considering component's moving 
+   * (host where it was is removed and host where it will be is added)
+   */
+  private _getHmHostsConsideringMoved(localDB: LocalDB, dependencies: Dependencies): string[] {
+    let hiveMSHosts = localDB.masterComponentHosts
+      .filter((host: any) => host.component === 'HIVE_METASTORE')
+      .map((host: any) => host.hostName);
+
+    // Remove source host and add target host
+    hiveMSHosts = hiveMSHosts.filter((host: string) => host !== dependencies.sourceHostName);
+    if (!hiveMSHosts.includes(dependencies.targetHostName)) {
+      hiveMSHosts.push(dependencies.targetHostName);
+    }
+
+    return Array.from(new Set(hiveMSHosts)); // ensure unique hosts
+  }
+
+  // Singleton pattern for compatibility with Step3
+  public static getInstance(): MoveHmConfigInitializer {
+    if (!MoveHmConfigInitializer.instance) {
+      MoveHmConfigInitializer.instance = new MoveHmConfigInitializer();
+    }
+    return MoveHmConfigInitializer.instance;
+  }
+
+  public static setup(settings: any): void {
+    const instance = MoveHmConfigInitializer.getInstance();
+    instance.setup(settings);
+  }
+
+  public static cleanup(): void {
+    const instance = MoveHmConfigInitializer.getInstance();
+    instance.cleanup();
+  }
+
+  public static initialValue(configProperty: ConfigProperty, localDB: LocalDB, dependencies: Dependencies): ConfigProperty {
+    const instance = MoveHmConfigInitializer.getInstance();
+    return instance.initialValue(configProperty, localDB, dependencies);
+  }
+}
+
+export default MoveHmConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/MoveHsConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveHsConfigInitializer.ts
new file mode 100644
index 0000000000..bbc3aa1d0a
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveHsConfigInitializer.ts
@@ -0,0 +1,72 @@
+/**
+ * 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 { MoveHiveComponentConfigInitializer } from './MoveHiveComponentConfigInitializer';
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+/**
+ * Initializer for configs which should be affected when Hive Server is moved from one host to another
+ */
+export class MoveHsConfigInitializer extends MoveHiveComponentConfigInitializer {
+  private static instance: MoveHsConfigInitializer;
+
+  constructor() {
+    super();
+    
+    this.initializers = {
+      'hadoop.proxyuser.{{hiveUser}}.hosts': MoveHiveComponentConfigInitializer.getHostsWithComponentsConfig(
+        ['HIVE_SERVER', 'HIVE_METASTORE', 'HIVE_SERVER_INTERACTIVE'], 
+        'HIVE_SERVER'
+      )
+    };
+  }
+
+  // Singleton pattern for compatibility with Step3
+  public static getInstance(): MoveHsConfigInitializer {
+    if (!MoveHsConfigInitializer.instance) {
+      MoveHsConfigInitializer.instance = new MoveHsConfigInitializer();
+    }
+    return MoveHsConfigInitializer.instance;
+  }
+
+  public static setup(settings: any): void {
+    const instance = MoveHsConfigInitializer.getInstance();
+    instance.setup(settings);
+  }
+
+  public static cleanup(): void {
+    const instance = MoveHsConfigInitializer.getInstance();
+    instance.cleanup();
+  }
+
+  public static initialValue(configProperty: ConfigProperty, localDB: LocalDB, dependencies: Dependencies): ConfigProperty {
+    const instance = MoveHsConfigInitializer.getInstance();
+    return instance.initialValue(configProperty, localDB, dependencies);
+  }
+}
+
+export default MoveHsConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/MoveNameNodeConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveNameNodeConfigInitializer.ts
new file mode 100644
index 0000000000..ccd61b86ee
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveNameNodeConfigInitializer.ts
@@ -0,0 +1,243 @@
+/**
+ * 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.
+ */
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+
+import {
+  MoveComponentConfigInitializer,
+  ReassignComponentDependencies,
+} from "./MoveComponentConfigInitializer";
+
+type ConfigProperty = {
+  name: string;
+  value: string | number;
+  filename: string;
+  recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+/**
+ * Initializer for configs which should be affected when NameNode is moved from one host to another
+ * If NameNode HA-mode is already activated, several configs are also updated
+ */
+export class MoveNameNodeConfigInitializer extends MoveComponentConfigInitializer {
+  private static instance: MoveNameNodeConfigInitializer;
+
+  constructor() {
+    super();
+
+    // Initialize the standard initializers for NameNode configs
+    this.initializers = {
+      "dfs.namenode.http-address.{{namespaceId}}.{{suffix}}":
+        MoveComponentConfigInitializer.getTargetHostConfig(50070),
+      "dfs.namenode.https-address.{{namespaceId}}.{{suffix}}":
+        MoveComponentConfigInitializer.getTargetHostConfig(50470),
+      "dfs.namenode.rpc-address.{{namespaceId}}.{{suffix}}":
+        MoveComponentConfigInitializer.getTargetHostConfig(8020),
+      "dfs.namenode.servicerpc-address.{{namespaceId}}.{{suffix}}":
+        MoveComponentConfigInitializer.getTargetHostConfig(8021),
+      "dfs.namenode.lifeline.rpc-address.{{namespaceId}}.{{suffix}}":
+        MoveComponentConfigInitializer.getTargetHostConfig(8050),
+
+      // 'dfs.namenode.http-address': MoveComponentConfigInitializer.getTargetHostConfig(50070),
+      // 'dfs.namenode.https-address': MoveComponentConfigInitializer.getTargetHostConfig(50470),
+      // 'dfs.namenode.rpc-address': MoveComponentConfigInitializer.getTargetHostConfig(8020),
+      // 'fs.defaultFS': MoveComponentConfigInitializer.getTargetHostConfig(8020, 'hdfs://')
+    };
+
+    // Initialize unique initializers for special handling
+    this.uniqueInitializers = {
+      "instance.volumes": "_initInstanceVolumes",
+      "instance.volumes.replacements": "_initInstanceVolumesReplacements",
+      "hbase.rootdir": "_initHbaseRootDir",
+      hawq_dfs_url: "_initHawqDfsUrl",
+    };
+  }
+
+  /**
+   * Static method to get singleton instance
+   */
+  public static getInstance(): MoveNameNodeConfigInitializer {
+    if (!MoveNameNodeConfigInitializer.instance) {
+      MoveNameNodeConfigInitializer.instance =
+        new MoveNameNodeConfigInitializer();
+    }
+    return MoveNameNodeConfigInitializer.instance;
+  }
+
+  /**
+   * Static setup method for compatibility with Step3
+   */
+  public static setup(settings: any): void {
+    const instance = MoveNameNodeConfigInitializer.getInstance();
+    instance.setup(settings);
+  }
+
+  /**
+   * Static cleanup method for compatibility with Step3
+   */
+  public static cleanup(): void {
+    const instance = MoveNameNodeConfigInitializer.getInstance();
+    instance.cleanup();
+  }
+
+  /**
+   * Static method to get initial value for compatibility
+   */
+  public static initialValue(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const instance = MoveNameNodeConfigInitializer.getInstance();
+    const result = instance.initialValue(configProperty, localDB, dependencies);
+
+    return result;
+  }
+
+  /**
+   * Unique initializer for instance.volumes config
+   * Value example: 'hdfs://host1:8020/apps/accumulo/data'
+   */
+
+  //@ts-ignore
+  private _initInstanceVolumes(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const reassignDeps = dependencies as ReassignComponentDependencies;
+
+    // Process regardless of HA status
+    if (this._isServiceInstalled(localDB, "ACCUMULO")) {
+      let value = String(configProperty.value);
+      value = value.replace(
+        /\/\/[^\/]*/,
+        "//" + reassignDeps.targetHostName + ":8020"
+      );
+      configProperty.value = value;
+      configProperty.recommendedValue = value;
+    }
+    return configProperty;
+  }
+
+  /**
+   * Unique initializer for instance.volumes.replacements config
+   * Value example: 'hdfs://host1:8020/apps/accumulo/data hdfs://host2:8020/apps/accumulo/data'
+   */
+  //@ts-ignore
+  private _initInstanceVolumesReplacements(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const reassignDeps = dependencies as ReassignComponentDependencies;
+
+    // Process regardless of HA status
+    if (this._isServiceInstalled(localDB, "ACCUMULO")) {
+      const target =
+        "hdfs://" +
+        reassignDeps.targetHostName +
+        ":8020" +
+        "/apps/accumulo/data";
+      const source =
+        "hdfs://" +
+        reassignDeps.sourceHostName +
+        ":8020" +
+        "/apps/accumulo/data";
+      const value = source + " " + target;
+      configProperty.value = value;
+      configProperty.recommendedValue = value;
+    }
+    return configProperty;
+  }
+
+  /**
+   * Unique initializer for hbase.rootdir config (for HBASE service)
+   */
+  //@ts-ignore
+  private _initHbaseRootDir(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const reassignDeps = dependencies as ReassignComponentDependencies;
+
+    // Process regardless of HA status
+    if (
+      this._isServiceInstalled(localDB, "HBASE") &&
+      configProperty.filename === "hbase-site"
+    ) {
+      let value = String(configProperty.value);
+      value = value.replace(
+        /\/\/[^\/]*/,
+        "//" + reassignDeps.targetHostName + ":8020"
+      );
+      configProperty.value = value;
+      configProperty.recommendedValue = value;
+    }
+    return configProperty;
+  }
+
+  /**
+   * Unique initializer for hawq_dfs_url config (for HAWQ service)
+   */
+  // @ts-ignore
+  private _initHawqDfsUrl(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies
+  ): ConfigProperty {
+    const reassignDeps = dependencies as ReassignComponentDependencies;
+
+    // Process regardless of HA status
+    if (
+      this._isServiceInstalled(localDB, "HAWQ") &&
+      configProperty.filename === "hawq-site"
+    ) {
+      let value = String(configProperty.value);
+      value = value.replace(/(.*):/, reassignDeps.targetHostName + ":");
+      configProperty.value = value;
+      configProperty.recommendedValue = value;
+    }
+    return configProperty;
+  }
+
+  /**
+   * Helper method to check if HA is enabled
+   */
+  //@ts-ignore
+  private _isHaEnabled(localDB: LocalDB): boolean {
+    // Check if HA is enabled by looking at the localDB
+    return localDB.isHaEnabled || false;
+  }
+
+  /**
+   * Helper method to check if a service is installed
+   */
+  private _isServiceInstalled(localDB: LocalDB, serviceName: string): boolean {
+    return (
+      localDB.installedServices &&
+      localDB.installedServices.includes(serviceName)
+    );
+  }
+}
+
+export default MoveNameNodeConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/MoveOSConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveOSConfigInitializer.ts
new file mode 100644
index 0000000000..45aaf3c146
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveOSConfigInitializer.ts
@@ -0,0 +1,69 @@
+/**
+ * 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 { MoveComponentConfigInitializer } from './MoveComponentConfigInitializer';
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+/**
+ * Initializer for configs which should be affected when Oozie Server is moved from one host to another
+ */
+export class MoveOSConfigInitializer extends MoveComponentConfigInitializer {
+  private static instance: MoveOSConfigInitializer;
+
+  constructor() {
+    super();
+    
+    this.initializers = {
+      'hadoop.proxyuser.{{oozieUser}}.hosts': MoveComponentConfigInitializer.getHostsWithComponentConfig('OOZIE_SERVER')
+    };
+  }
+
+  // Singleton pattern for compatibility with Step3
+  public static getInstance(): MoveOSConfigInitializer {
+    if (!MoveOSConfigInitializer.instance) {
+      MoveOSConfigInitializer.instance = new MoveOSConfigInitializer();
+    }
+    return MoveOSConfigInitializer.instance;
+  }
+
+  public static setup(settings: any): void {
+    const instance = MoveOSConfigInitializer.getInstance();
+    instance.setup(settings);
+  }
+
+  public static cleanup(): void {
+    const instance = MoveOSConfigInitializer.getInstance();
+    instance.cleanup();
+  }
+
+  public static initialValue(configProperty: ConfigProperty, localDB: LocalDB, dependencies: Dependencies): ConfigProperty {
+    const instance = MoveOSConfigInitializer.getInstance();
+    return instance.initialValue(configProperty, localDB, dependencies);
+  }
+}
+
+export default MoveOSConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/MoveRmConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveRmConfigInitializer.ts
new file mode 100644
index 0000000000..4d49b4ec8d
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveRmConfigInitializer.ts
@@ -0,0 +1,195 @@
+/**
+ * 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 { MoveComponentConfigInitializer, MoveInitializer } from './MoveComponentConfigInitializer';
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+export interface RmHaInitializer extends MoveInitializer {
+  rmHaShouldBeEnabled: boolean;
+}
+
+/**
+ * Initializer for configs which should be affected when Resource Manager is moved from one host to another
+ * If Resource Manager HA-mode is already activated, several configs are also updated
+ */
+export class MoveRmConfigInitializer extends MoveComponentConfigInitializer {
+  private static instance: MoveRmConfigInitializer;
+
+  constructor() {
+    super();
+    this.initializerTypes = [
+      ...this.initializerTypes,
+      { name: 'rm_ha_depended', method: '_initAsRmHaDepended' },
+      { name: 'rm_ha_hawq', method: '_initAsRmHaHawq' }
+    ];
+
+    this.initializers = {
+      'yarn.resourcemanager.hostname.{{suffix}}': MoveRmConfigInitializer.getRmHaDependedConfig(true),
+      'yarn.resourcemanager.webapp.address.{{suffix}}': MoveRmConfigInitializer.getRmHaDependedConfig(true),
+      'yarn.resourcemanager.webapp.https.address.{{suffix}}': MoveRmConfigInitializer.getRmHaDependedConfig(true),
+      'yarn.resourcemanager.resource-tracker.address.{{suffix}}': MoveRmConfigInitializer.getRmHaDependedConfig(true),
+      'yarn.resourcemanager.address.{{suffix}}': MoveRmConfigInitializer.getRmHaDependedConfig(true),
+      'yarn.resourcemanager.ha': MoveRmConfigInitializer.getRmHaHawqConfig(true),
+      'yarn.resourcemanager.scheduler.ha': MoveRmConfigInitializer.getRmHaHawqConfig(true)
+    };
+  }
+
+  /**
+   * Check if ResourceManager HA is enabled
+   */
+  private _isRMHaEnabled(localDB: LocalDB): boolean {
+    // Check if there are multiple ResourceManager instances
+    const rmHosts = localDB.masterComponentHosts
+      .filter((host: any) => host.component === 'RESOURCEMANAGER')
+      .map((host: any) => host.hostName);
+    return rmHosts.length > 1;
+  }
+
+  /**
+   * Initializer for configs with value equal to the target hostName
+   * and based on ResourceManager HA status
+   * Value example: 'host1:port1'
+   */
+  protected _initAsRmHaDepended(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies,
+    initializer: RmHaInitializer
+  ): ConfigProperty {
+    const isRMHaEnabled = this._isRMHaEnabled(localDB);
+    
+    if (isRMHaEnabled === initializer.rmHaShouldBeEnabled) {
+      const value = String(configProperty.value);
+      const parts = value.split(':');
+      parts[0] = dependencies.targetHostName;
+      const newValue = parts.join(':');
+      configProperty.value = newValue;
+      configProperty.recommendedValue = newValue;
+    }
+    return configProperty;
+  }
+
+  /**
+   * This function generates "rm1_host:port,rm2_host:port" for HAWQ configuration (RM HA specific)
+   * 
+   * configProperty = {
+   *   filename: "yarn-client",
+   *   name: "yarn.resourcemanager.ha",
+   *   value: "ip-10-32-36-162.ore1.vpc.pivotal.io:8050"
+   * }
+   *
+   * dependencies = {
+   *   rm1: "ip-10-32-38-225.ore1.vpc.pivotal.io",
+   *   rm2: "ip-10-32-38-162.ore1.vpc.pivotal.io",
+   *   sourceHostName: "ip-10-32-36-162.ore1.vpc.pivotal.io",
+   *   targetHostName: "ip-10-32-38-34.ore1.vpc.pivotal.io"
+   * }
+   */
+  protected _initAsRmHaHawq(
+    configProperty: ConfigProperty,
+    localDB: LocalDB,
+    dependencies: Dependencies,
+    initializer: RmHaInitializer
+  ): ConfigProperty {
+    const isRMHaEnabled = this._isRMHaEnabled(localDB);
+    
+    if (isRMHaEnabled === initializer.rmHaShouldBeEnabled) {
+      // Which of rm1 and rm2 is changed?
+      let rm1: string, rm2: string;
+      
+      if (dependencies.rm1 === dependencies.sourceHostName) {
+        rm1 = dependencies.targetHostName;
+        rm2 = dependencies.rm2;
+      } else {
+        rm1 = dependencies.rm1;
+        rm2 = dependencies.targetHostName;
+      }
+
+      // Default ports from Hadoop YARN configuration
+      const DEFAULT_RM_PORT = 8032;
+      const DEFAULT_RM_SCHEDULER_PORT = 8030;
+
+      let newValue: string;
+      if (configProperty.name === 'yarn.resourcemanager.ha') {
+        newValue = `${rm1}:${DEFAULT_RM_PORT},${rm2}:${DEFAULT_RM_PORT}`;
+      } else {
+        newValue = `${rm1}:${DEFAULT_RM_SCHEDULER_PORT},${rm2}:${DEFAULT_RM_SCHEDULER_PORT}`;
+      }
+
+      configProperty.value = newValue;
+      configProperty.recommendedValue = newValue;
+    }
+    return configProperty;
+  }
+
+  /**
+   * Settings for rm_ha_depended-initializer
+   * Used for configs with value equal to the host name (host where component is moved)
+   */
+  public static getRmHaDependedConfig(rmHaShouldBeEnabled: boolean): RmHaInitializer {
+    return {
+      type: 'rm_ha_depended',
+      rmHaShouldBeEnabled: Boolean(rmHaShouldBeEnabled)
+    };
+  }
+
+  /**
+   * Settings for rm_ha_hawq-initializer
+   * Used for HAWQ RM HA configurations
+   */
+  public static getRmHaHawqConfig(rmHaShouldBeEnabled: boolean): RmHaInitializer {
+    return {
+      type: 'rm_ha_hawq',
+      rmHaShouldBeEnabled: Boolean(rmHaShouldBeEnabled)
+    };
+  }
+
+  // Singleton pattern for compatibility with Step3
+  public static getInstance(): MoveRmConfigInitializer {
+    if (!MoveRmConfigInitializer.instance) {
+      MoveRmConfigInitializer.instance = new MoveRmConfigInitializer();
+    }
+    return MoveRmConfigInitializer.instance;
+  }
+
+  public static setup(settings: any): void {
+    const instance = MoveRmConfigInitializer.getInstance();
+    instance.setup(settings);
+  }
+
+  public static cleanup(): void {
+    const instance = MoveRmConfigInitializer.getInstance();
+    instance.cleanup();
+  }
+
+  public static initialValue(configProperty: ConfigProperty, localDB: LocalDB, dependencies: Dependencies): ConfigProperty {
+    const instance = MoveRmConfigInitializer.getInstance();
+    return instance.initialValue(configProperty, localDB, dependencies);
+  }
+}
+
+export default MoveRmConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/MoveWsConfigInitializer.ts b/ambari-web/latest/src/Initializers/MoveWsConfigInitializer.ts
new file mode 100644
index 0000000000..e95eb1058a
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/MoveWsConfigInitializer.ts
@@ -0,0 +1,72 @@
+/**
+ * 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 { MoveHiveComponentConfigInitializer } from './MoveHiveComponentConfigInitializer';
+
+type ConfigProperty = {
+    name: string;
+    value: string | number;
+    filename: string;
+    recommendedValue?: string | number;
+};
+
+type LocalDB = Record<string, any>;
+type Dependencies = Record<string, any>;
+
+/**
+ * Initializer for configs which should be affected when WebHCat Server is moved from one host to another
+ */
+export class MoveWsConfigInitializer extends MoveHiveComponentConfigInitializer {
+  private static instance: MoveWsConfigInitializer;
+
+  constructor() {
+    super();
+    
+    this.initializers = {
+      'hadoop.proxyuser.{{webhcatUser}}.hosts': MoveHiveComponentConfigInitializer.getHostsWithComponentsConfig(
+        ['WEBHCAT_SERVER'], 
+        'WEBHCAT_SERVER'
+      )
+    };
+  }
+
+  // Singleton pattern for compatibility with Step3
+  public static getInstance(): MoveWsConfigInitializer {
+    if (!MoveWsConfigInitializer.instance) {
+      MoveWsConfigInitializer.instance = new MoveWsConfigInitializer();
+    }
+    return MoveWsConfigInitializer.instance;
+  }
+
+  public static setup(settings: any): void {
+    const instance = MoveWsConfigInitializer.getInstance();
+    instance.setup(settings);
+  }
+
+  public static cleanup(): void {
+    const instance = MoveWsConfigInitializer.getInstance();
+    instance.cleanup();
+  }
+
+  public static initialValue(configProperty: ConfigProperty, localDB: LocalDB, dependencies: Dependencies): ConfigProperty {
+    const instance = MoveWsConfigInitializer.getInstance();
+    return instance.initialValue(configProperty, localDB, dependencies);
+  }
+}
+
+export default MoveWsConfigInitializer;
diff --git a/ambari-web/latest/src/Initializers/UtilitiesForInitialziers.ts b/ambari-web/latest/src/Initializers/UtilitiesForInitialziers.ts
new file mode 100644
index 0000000000..7b758d91db
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/UtilitiesForInitialziers.ts
@@ -0,0 +1,168 @@
+/**
+ * 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.
+ */
+
+type SiteConfigs = Record<string, string>;
+//@ts-ignore
+type UniqueHostsListParser = {
+    type: string;
+    propertyName: string;
+    method: (value: string) => string;
+};
+
+interface MasterComponent {
+    component: string;
+    hostName: string;
+    isInstalled: boolean;
+}
+
+interface HiveHostsParams {
+    fromDeleteHost: boolean;
+    deleteHiveMetaStore: boolean;
+    deleteHiveServer: boolean;
+    deleteWebHCatServer: boolean;
+    hiveMetastoreHost: string | null;
+    contentHostName: string;
+    bootstrapHostsMapping: (componentName: string) => MasterComponent[];
+}
+
+class UtilitiesForInitialziers {
+    static updateHostsListValue(
+        siteConfigs: SiteConfigs,
+        propertyType: string,
+        propertyName: string,
+        hostsList: string,
+        isArray: boolean
+    ): string {
+        const uniqueHostsListParsers = [
+            {
+                propertyName: "templeton.hive.properties",
+                type: "webhcat-site",
+                method: "getTempletonHiveHosts",
+            },
+        ];
+        let value = hostsList;
+        let propertyHosts = siteConfigs[propertyName] || "";
+        let hostsToSet = hostsList;
+
+        const parser = uniqueHostsListParsers.find(
+            (property) =>
+                property.type === propertyType && property.propertyName === propertyName
+        );
+
+        if (parser) {
+            //@ts-ignore
+            propertyHosts = parser.method(propertyHosts);
+            //@ts-ignore
+            hostsToSet = parser.method(hostsToSet);
+        } else {
+            if (isArray) {
+                const pattern = /(^\[|]$)/g;
+                propertyHosts = propertyHosts.replace(pattern, "");
+                hostsToSet = hostsToSet.replace(pattern, "");
+            }
+            propertyHosts = propertyHosts.split(",").join(",");
+            hostsToSet = hostsToSet.split(",").join(",");
+        }
+
+        if (siteConfigs[propertyName]) {
+            const diffLength = propertyHosts
+                .split(",")
+                .filter((hostName) => !hostsToSet.split(",").includes(hostName)).length;
+
+            if (
+                diffLength === 0 &&
+                propertyHosts.split(",").length === hostsToSet.split(",").length
+            ) {
+                value = siteConfigs[propertyName];
+            }
+        }
+
+        siteConfigs[propertyName] = value;
+        return value;
+    }
+    static getHiveHosts(params: HiveHostsParams): MasterComponent[] {
+        const {
+            fromDeleteHost,
+            deleteHiveMetaStore,
+            deleteHiveServer,
+            deleteWebHCatServer,
+            hiveMetastoreHost,
+            // webhcatServerHost,
+            // bootstrapHostsMapping,
+        } = params;
+
+        let removePerformed =
+            fromDeleteHost ||
+            deleteHiveMetaStore ||
+            deleteHiveServer ||
+            deleteWebHCatServer;
+
+        const hiveMasterComponents = ["HIVE_METASTORE", "HIVE_SERVER"];
+        let masterComponentsMap = hiveMasterComponents
+            .map((componentName) =>
+                UtilitiesForInitialziers.bootstrapHostsMapping(componentName)
+            )
+            .reduce((p, c) => p.concat(c), []);
+
+        if (removePerformed) {
+            masterComponentsMap = masterComponentsMap.map((masterComponent) => {
+                //@ts-ignore
+                masterComponent.isInstalled =
+                    //@ts-ignore
+                    masterComponent.hostName !== contentHostName;
+                return masterComponent;
+            });
+        }
+
+        if (hiveMetastoreHost) {
+            masterComponentsMap.push({
+                component: "HIVE_METASTORE",
+                hostName: hiveMetastoreHost,
+                isInstalled: !removePerformed,
+            });
+        }
+
+        // if (webhcatServerHost) {
+        //     masterComponentsMap.push({
+        //         component: 'WEBHCAT_SERVER',
+        //         hostName: webhcatServerHost,
+        //         isInstalled: !removePerformed,
+        //     });
+        // }
+
+        return masterComponentsMap;
+    }
+
+    //@ts-ignore
+    static bootstrapHostsMapping(
+        componentName: string,
+        hostNames?: string[]
+        //@ts-ignore
+    ): HostMapping[] {
+        if (!hostNames) {
+            hostNames = [];
+        }
+        return hostNames.map((hostName) => ({
+            component: componentName,
+            hostName: hostName,
+            isInstalled: true,
+        }));
+    }
+}
+
+export default UtilitiesForInitialziers;
diff --git a/ambari-web/latest/src/Initializers/WizardConfigInitializer.ts b/ambari-web/latest/src/Initializers/WizardConfigInitializer.ts
new file mode 100644
index 0000000000..f75f8e1798
--- /dev/null
+++ b/ambari-web/latest/src/Initializers/WizardConfigInitializer.ts
@@ -0,0 +1,632 @@
+/**
+ * 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 {
+  cloneDeep,
+  filter,
+  find,
+  get,
+  isFunction,
+  map,
+  sortBy,
+  toArray,
+  uniq,
+} from "lodash";
+import stringUtils from "../Utils/StringUtilsObj";
+
+function getZKBasedConfig() {
+  return {
+    type: "zookeeper_based",
+  };
+}
+const hostWithPort = "([\\w|\\.]*)(?=:)";
+const hostWithPrefix = "://" + hostWithPort;
+
+function WizardConfigInitializer(
+  configProperty: any,
+  _localDB: any,
+  _dependencies: any
+) {
+  const obj: any = {
+    _setRangerAdminPassword: () => {
+      var value = "P1!q" + stringUtils.getRandomString(12);
+      configProperty = {
+        ...configProperty,
+        ...{ value: value, recommendedValue: value, retypedPassword: value, confirmPassword: value },
+      };
+      return configProperty;
+    },
+
+    initializerTypes: [
+      {
+        name: "zookeeper_based",
+        method: "_initAsZookeeperServersList",
+      },
+      {
+        name: "host_with_component",
+        method: "_initAsHostWithComponent",
+      },
+      {
+        name: "hosts_with_components",
+        method: "_initAsHostsWithComponents",
+      },
+
+      {
+        name: "hosts_list_with_component",
+        method: "_initAsHostsListWithComponent",
+      },
+    ],
+    _initAsHostsListWithComponent: (
+      configProperty: any,
+      localDB: any,
+      _dependencies: any,
+      initializer?: any
+    ) => {
+      var hostNames = map(
+        filter(
+          filter(localDB.masterComponentHosts, [
+            "component",
+            initializer?.component,
+          ]),
+          ["isInstalled", initializer?.componentExists]
+        ),
+        "hostName"
+      ).join(initializer?.modifier?.delimiter);
+      configProperty = {
+        ...configProperty,
+        ...{
+          value: hostNames,
+          recommendedValue: hostNames,
+        },
+      };
+
+      return configProperty;
+    },
+    _initAsHostsWithComponents: (
+      configProperty: any,
+      localDB: any,
+      _dependencies: any,
+      initializer?: any
+    ) => {
+      let hostNames: any = map(
+        sortBy(
+          localDB.masterComponentHosts.filter(function (masterComponent: any) {
+            var hasFound = initializer?.components?.includes(
+              masterComponent.component
+            );
+            if (initializer?.isInstalled) {
+              return hasFound;
+            }
+            return (
+              hasFound &&
+              masterComponent?.isInstalled === initializer?.isInstalled
+            );
+          }),
+          "hostName"
+        ),
+        "hostName"
+      );
+      if (!initializer) {
+        hostNames = uniq(hostNames).join(",");
+      }
+      configProperty = {
+        ...configProperty,
+        ...{
+          value: hostNames,
+          recommendedValue: hostNames,
+        },
+      };
+      return configProperty;
+    },
+    _initAsHostWithComponent: (
+      configProperty: any,
+      localDB: any,
+      _dependencies: any,
+      initializer?: any
+    ) => {
+      var component = find(localDB.masterComponentHosts, [
+        "component",
+        initializer?.component,
+      ]);
+      if (!component) {
+        return configProperty;
+      }
+      if (initializer.modifier) {
+        let replaceWith =
+          (initializer.modifier.prefix || "") +
+          component.hostName +
+          (initializer.modifier.suffix || "");
+        setRecommendedValue(
+          configProperty,
+          initializer.modifier.regex,
+          replaceWith
+        );
+      } else {
+        const changedValue = configProperty.value.split(":");
+        changedValue[0] = component.hostName;
+        configProperty = {
+          ...configProperty,
+          ...{
+            recommendedValue: component.hostName,
+            value: changedValue.join(":"),
+          },
+        };
+      }
+
+      return configProperty;
+    },
+    _initHiveDatabaseValue: (configProperty: any) => {
+      var newMySQLDBOption = find(get(configProperty, "options"), [
+        "displayName",
+        "New MySQL Database",
+      ]);
+      // if (newMySQLDBOption) {
+      //   var isNewMySQLDBOptionHidden =
+      //     get("supports.alwaysEnableManagedMySQLForHive") &&
+      //     App.get("router.currentState.name") !== "configs" &&
+      //     !App.get("isManagedMySQLForHiveEnabled");
+      //   if (
+      //     isNewMySQLDBOptionHidden &&
+      //     Em.get(configProperty, "value") === "New MySQL Database"
+      //   ) {
+      //     Em.set(configProperty, "value", "Existing MySQL Database");
+      //   }
+      //   Em.set(newMySQLDBOption, "hidden", isNewMySQLDBOptionHidden);
+      // }
+      console.log("newMySQLDBOption", newMySQLDBOption);
+
+      return configProperty;
+    },
+    _initTempletonHiveProperties: (
+      configProperty: any,
+      localDB: any,
+      dependencies: any
+    ) => {
+      var hiveMSUris = self
+        .getHiveMetastoreUris(
+          localDB.masterComponentHosts,
+          dependencies["hive.metastore.uris"]
+        )
+        .replace(",", "\\,");
+      if (/\/\/localhost:/g.test(get(configProperty, "value"))) {
+        configProperty.recommendedValue =
+          get(configProperty, "value") + ",hive.metastore.execute.setugi=true";
+      }
+      setRecommendedValue(
+        configProperty,
+        "(hive\\.metastore\\.uris=)([^\\,]+)",
+        "$1" + hiveMSUris
+      );
+      return configProperty;
+    },
+    _initHBaseZookeeperQuorum: (configProperty: any, localDB: any) => {
+      if ("hbase-site.xml" === get(configProperty, "fileName")) {
+        const zkHosts = uniq(map(
+          filter(localDB.masterComponentHosts, [
+            "component",
+            "ZOOKEEPER_SERVER",
+          ]),
+          "hostName"
+        ));
+        setRecommendedValue(configProperty, "(.*)", zkHosts.join(","));
+      }
+      return configProperty;
+    },
+    _initRangerHost: (configProperty: any, localDB: any) => {
+      var rangerAdminHost = find(localDB.masterComponentHosts, [
+        "component",
+        "RANGER_ADMIN",
+      ]);
+      if (rangerAdminHost) {
+        configProperty = {
+          ...configProperty,
+          ...{
+            value: rangerAdminHost.hostName,
+            recommendedValue: rangerAdminHost.hostName,
+          },
+        };
+      } else {
+        configProperty = {
+          ...configProperty,
+          ...{
+            isVisible: "false",
+            isRequired: "false",
+          },
+        };
+      }
+      return configProperty;
+    },
+    _initAsZookeeperServersList: (configProperty: any, localDB: any) => {
+      var zkHosts = map(
+        filter(localDB.masterComponentHosts, ["component", "ZOOKEEPER_SERVER"]),
+        "hostName"
+      );
+      var zkHostPort = zkHosts;
+      var regex = "\\w*:(\\d+)"; //regex to fetch the port
+      var portValue =
+        get(configProperty, "recommendedValue") &&
+        get(configProperty, "recommendedValue").match(new RegExp(regex));
+      if (!portValue) {
+        return configProperty;
+      }
+      if (portValue[1]) {
+        for (var i = 0; i < zkHosts.length; i++) {
+          zkHostPort[i] = zkHosts[i] + ":" + portValue[1];
+        }
+      }
+      setRecommendedValue(configProperty, "(.*)", zkHostPort);
+      return configProperty;
+    },
+    _initYarnRMzkAddress: (
+      configProperty: any,
+      localDB: any,
+      dependencies: any
+    ) => {
+      const value = filter(localDB.masterComponentHosts, [
+        "component",
+        "ZOOKEEPER_SERVER",
+      ])
+        .map(function (component) {
+          return component.hostName + ":" + dependencies.clientPort;
+        })
+        .join(",");
+
+      configProperty = {
+        ...configProperty,
+        ...{
+          value: value,
+          recommendedValue: value,
+        },
+      };
+
+      return configProperty;
+    },
+    _initHiveMetastoreUris: (
+      configProperty: any,
+      localDB: any,
+      dependencies: any
+    ) => {
+      const fileName = get(configProperty, "fileName");
+      const isHiveSite = fileName.endsWith(".xml")
+        ? fileName.slice(0, -4)
+        : fileName;
+      if (isHiveSite) {
+        var hiveMSUris = self.getHiveMetastoreUris(
+          localDB.masterComponentHosts,
+          dependencies["hive.metastore.uris"]
+        );
+        if (hiveMSUris) {
+          setRecommendedValue(configProperty, "(.*)", hiveMSUris);
+        }
+      }
+      return configProperty;
+    },
+
+    initAtlasRestAddress: (
+      configProperty: any,
+      localDB: any,
+      dependencies: any
+    ) => {
+      var atlasTls = dependencies["atlas.enableTLS"];
+      var httpPort = dependencies["atlas.server.http.port"];
+      var httpsPort = dependencies["atlas.server.https.port"];
+      var protocol = atlasTls ? "https" : "http";
+      var port = atlasTls ? httpsPort : httpPort;
+      var value = filter(localDB.masterComponentHosts, [
+        "component",
+        "ZOOKEEPER_SERVER",
+      ])
+        .map(function (component) {
+          return protocol + "://" + component.hostName + ":" + port;
+        })
+        .join(",");
+      configProperty = {
+        ...configProperty,
+        ...{
+          value,
+          recommendedValue: value,
+        },
+      };
+      return configProperty;
+    },
+    getHiveMetastoreUris: (hosts: any, recommendedValue: any) => {
+      var hiveMSHosts = map(
+          filter(hosts, ["component", "HIVE_METASTORE"]),
+          "hostName"
+        ),
+        hiveMSUris = hiveMSHosts,
+        regex = "\\w*:(\\d+)",
+        portValue =
+          recommendedValue && recommendedValue.match(new RegExp(regex));
+
+      if (!portValue) {
+        return "";
+      }
+      if (portValue[1]) {
+        for (var i = 0; i < hiveMSHosts.length; i++) {
+          hiveMSUris[i] = "thrift://" + hiveMSHosts[i] + ":" + portValue[1];
+        }
+      }
+      return hiveMSUris.join(",");
+    },
+
+    getSimpleComponentConfig: (component: any, withModifier?: any) => {
+      if (arguments.length === 1) {
+        withModifier = true;
+      }
+      let config: any = {
+        type: "host_with_component",
+        component: component,
+      };
+      if (withModifier) {
+        config.modifier = {
+          type: "regexp",
+          regex: hostWithPort,
+        };
+      }
+      return config;
+    },
+
+    getComponentConfigWithAffixes: (
+      component: any,
+      prefix: any,
+      suffix?: any
+    ) => {
+      prefix = prefix || "";
+      suffix = suffix || "";
+      return {
+        type: "host_with_component",
+        component: component,
+        modifier: {
+          type: "regexp",
+          regex: hostWithPrefix,
+          prefix: prefix,
+          suffix: suffix,
+        },
+      };
+    },
+
+    getComponentsHostsConfig: (
+      components: any,
+      asArray: any = false,
+      isInstalled?: any
+    ) => {
+      if (1 === arguments.length) {
+        asArray = false;
+      }
+      return {
+        type: "hosts_with_components",
+        components: toArray(components),
+        asArray: asArray,
+        isInstalled: isInstalled,
+      };
+    },
+  };
+  let self: any = obj;
+
+  const uniqueInitializers: any = {
+    ranger_admin_password: "_setRangerAdminPassword",
+    hive_database: "_initHiveDatabaseValue",
+    "templeton.hive.properties": "_initTempletonHiveProperties",
+    "hbase.zookeeper.quorum": "_initHBaseZookeeperQuorum",
+    "yarn.resourcemanager.zk-address": "_initYarnRMzkAddress",
+    RANGER_HOST: "_initRangerHost",
+    "hive.metastore.uris": "_initHiveMetastoreUris",
+  };
+  const initializers = {
+    "dfs.namenode.rpc-address": self.getSimpleComponentConfig("NAMENODE"),
+    "dfs.http.address": self.getSimpleComponentConfig("NAMENODE"),
+    "dfs.namenode.http-address": self.getSimpleComponentConfig("NAMENODE"),
+    "dfs.https.address": self.getSimpleComponentConfig("NAMENODE"),
+    "dfs.namenode.https-address": self.getSimpleComponentConfig("NAMENODE"),
+    "dfs.secondary.http.address":
+      self.getSimpleComponentConfig("SECONDARY_NAMENODE"),
+    "dfs.namenode.secondary.http-address":
+      self.getSimpleComponentConfig("SECONDARY_NAMENODE"),
+    "yarn.resourcemanager.hostname": self.getSimpleComponentConfig(
+      "RESOURCEMANAGER",
+      false
+    ),
+    "yarn.resourcemanager.resource-tracker.address":
+      self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    "yarn.resourcemanager.webapp.https.address":
+      self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    "yarn.resourcemanager.webapp.address":
+      self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    "yarn.resourcemanager.scheduler.address":
+      self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    "yarn.resourcemanager.address":
+      self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    "yarn.resourcemanager.admin.address":
+      self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    "yarn.timeline-service.webapp.address": self.getSimpleComponentConfig(
+      "APP_TIMELINE_SERVER"
+    ),
+    "yarn.timeline-service.webapp.https.address": self.getSimpleComponentConfig(
+      "APP_TIMELINE_SERVER"
+    ),
+    "yarn.timeline-service.address": self.getSimpleComponentConfig(
+      "APP_TIMELINE_SERVER"
+    ),
+    "mapred.job.tracker": self.getSimpleComponentConfig("JOBTRACKER"),
+    "mapred.job.tracker.http.address":
+      self.getSimpleComponentConfig("JOBTRACKER"),
+    "mapreduce.history.server.http.address":
+      self.getSimpleComponentConfig("HISTORYSERVER"),
+    "oozie.base.url": self.getComponentConfigWithAffixes("OOZIE_SERVER", "://"),
+    hawq_dfs_url: self.getSimpleComponentConfig("NAMENODE"),
+    hawq_rm_yarn_address: self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    hawq_rm_yarn_scheduler_address:
+      self.getSimpleComponentConfig("RESOURCEMANAGER"),
+    "fs.default.name": self.getComponentConfigWithAffixes("NAMENODE", "://"),
+    "fs.defaultFS": self.getComponentConfigWithAffixes("NAMENODE", "://"),
+    "hbase.rootdir": self.getComponentConfigWithAffixes("NAMENODE", "://"),
+    "instance.volumes": self.getComponentConfigWithAffixes("NAMENODE", "://"),
+    "yarn.log.server.url": self.getComponentConfigWithAffixes(
+      "HISTORYSERVER",
+      "://"
+    ),
+    "mapreduce.jobhistory.webapp.address":
+      self.getSimpleComponentConfig("HISTORYSERVER"),
+    "mapreduce.jobhistory.address":
+      self.getSimpleComponentConfig("HISTORYSERVER"),
+    "kafka.ganglia.metrics.host": self.getSimpleComponentConfig(
+      "GANGLIA_SERVER",
+      false
+    ),
+    hive_master_hosts: self.getComponentsHostsConfig([
+      "HIVE_METASTORE",
+      "HIVE_SERVER",
+    ]),
+    hadoop_host: self.getSimpleComponentConfig("NAMENODE", false),
+    "nimbus.host": self.getSimpleComponentConfig("NIMBUS", false),
+    "nimbus.seeds": self.getComponentsHostsConfig("NIMBUS", true),
+    "storm.zookeeper.servers": self.getComponentsHostsConfig(
+      "ZOOKEEPER_SERVER",
+      true
+    ),
+    hawq_master_address_host: self.getSimpleComponentConfig(
+      "HAWQMASTER",
+      false
+    ),
+    hawq_standby_address_host: self.getSimpleComponentConfig(
+      "HAWQSTANDBY",
+      false
+    ),
+
+    "*.broker.url": {
+      type: "host_with_component",
+      component: "FALCON_SERVER",
+      modifier: {
+        type: "regexp",
+        regex: "localhost",
+      },
+    },
+
+    "zookeeper.connect": getZKBasedConfig(),
+    "hive.zookeeper.quorum": getZKBasedConfig(),
+    "templeton.zookeeper.hosts": getZKBasedConfig(),
+    "hadoop.registry.zk.quorum": getZKBasedConfig(),
+    "hive.cluster.delegation.token.store.zookeeper.connectString":
+      getZKBasedConfig(),
+    "instance.zookeeper.host": getZKBasedConfig(),
+  };
+  function _defaultInitializer(
+    configProperty: any,
+    _localDB: any,
+    _dependencies: any
+  ) {
+    let args = [].slice.call(arguments);
+    var localInitializers: any = initializers;
+    var initializer = localInitializers[get(configProperty, "propertyName")];
+
+    if (initializer) {
+      let init = initializer;
+      let _args: any = [].slice.call(args);
+      const inferredVariabled = init?.type ? init.type : init;
+      let type = find(self.initializerTypes, ["name", inferredVariabled]);
+      // add initializer-settings
+      if (type) {
+        _args.push(init);
+        let methodName: any = type.method;
+        if (!isFunction(obj[methodName])) {
+          console.log(methodName, "is not a function");
+          // throw new Error("Method " + method + " is not defined");
+        }
+        if (init.isChecker) {
+          // method(_args);
+          // if (result === flowSkipNext()) {
+          //   i++; // skip next
+          // }
+          // else {
+          //   if (result === self.flowSkipAll()) {
+          //     break;
+          //   }
+          // }
+        } else {
+          configProperty = obj[methodName]?.(..._args); // call method with args
+        }
+      }
+    }
+    return configProperty;
+  }
+  function setRecommendedValue(
+    configProperty: any,
+    regex: any,
+    replaceWith: any
+  ) {
+    
+    var recommendedValue = get(configProperty, "recommendedValue");
+    recommendedValue = !recommendedValue ? (configProperty.value || "") : recommendedValue;
+    var re = new RegExp(regex);
+    
+   
+      recommendedValue = recommendedValue.replace(re, replaceWith);
+    
+    
+    
+    configProperty.recommendedValue = recommendedValue;
+    let value = !get(configProperty, "recommendedValue")
+      ? ""
+      : recommendedValue;
+    
+    // If final value is empty/undefined, fall back to current value
+    if (!value && configProperty.value) {
+      value = configProperty.value;
+      configProperty.recommendedValue = configProperty.value;
+      
+    }
+      
+    
+    configProperty.value = value;
+    configProperty.initialValue = value;
+    return configProperty;
+  }
+  const initialValue = (
+    configPropertyCopy: any,
+    localDB: any,
+    dependencies: any
+  ) => {
+    let configProperty = cloneDeep(configPropertyCopy);
+    var configName = get(configProperty, "propertyName");
+    var definedInitializers: any = initializers;
+    var initializer = definedInitializers[configName];
+    if (initializer) {
+      return _defaultInitializer(configProperty, localDB, dependencies);
+    }
+
+    var uniqueInitializerName: any = uniqueInitializers[configName];
+    if (uniqueInitializerName && typeof obj[uniqueInitializerName] === 'function') {
+      return obj[uniqueInitializerName](configProperty, localDB, dependencies);
+    }
+
+  
+    configProperty = {
+      ...configProperty,
+      ...{
+        initialValue: get(configProperty, "value"),
+      },
+    };
+    return configProperty;
+  };
+  return {
+    initialValue,
+  };
+}
+
+export default WizardConfigInitializer;
diff --git a/ambari-web/latest/src/Utils/StringUtilsObj.ts b/ambari-web/latest/src/Utils/StringUtilsObj.ts
new file mode 100644
index 0000000000..819c85efa4
--- /dev/null
+++ b/ambari-web/latest/src/Utils/StringUtilsObj.ts
@@ -0,0 +1,173 @@
+/**
+ * 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.
+ */
+
+interface StringUtils {
+  pad(str: string, len?: number, pad?: string, dir?: number): string;
+  underScoreToCamelCase(name: string): string;
+  getCamelCase(name: string | null): string | null;
+  compareVersions(first: string, second: string): number;
+  isSingleLine(string: string): boolean;
+  arrayToCSV(array: Array<Record<string, any>>): string;
+  getFileFromPath(path: string): string;
+  getPath(path: string): string;
+  getFormattedStringFromArray(array: string[], endSeparator?: string): string;
+  pluralize(count: number, singular: string, plural?: string): string;
+  htmlEntities(string: string): string;
+  escapeRegExp(str: string): string;
+  getRandomString(len: number, allowed?: string): string;
+  upperUnderscoreToText(string: string): string;
+  unicodeEscape(string: string, regexp?: RegExp): string;
+}
+ 
+const STR_PAD_LEFT = 1;
+const STR_PAD_RIGHT = 2;
+const STR_PAD_BOTH = 3;
+ 
+const stringUtilsObj: StringUtils = {
+  pad(str: string, len: number = 0, pad: string = ' ', dir: number = STR_PAD_RIGHT): string {
+    if (len + 1 >= str.length) {
+      switch (dir) {
+        case STR_PAD_LEFT:
+          str = Array(len + 1 - str.length).join(pad) + str;
+          break;
+        case STR_PAD_BOTH:
+          const padlen = len - str.length;
+          const right = Math.ceil(padlen / 2);
+          const left = padlen - right;
+          str = Array(left + 1).join(pad) + str + Array(right + 1).join(pad);
+          break;
+        default:
+          str = str + Array(len + 1 - str.length).join(pad);
+          break;
+      }
+    }
+    return str;
+  },
+ 
+  underScoreToCamelCase(name: string): string {
+    return name.replace(/_\w/g, (str) => str[1].toUpperCase());
+  },
+ 
+  getCamelCase(name: string | null): string | null {
+    if (name != null) {
+      return name.toLowerCase().replace(/(\b\w)/g, (f) => f.toUpperCase());
+    }
+    return name;
+  },
+ 
+  compareVersions(first: string, second: string): number {
+    if (!(typeof first === 'string' && typeof second === 'string')) {
+      return -1;
+    }
+    if (first === '' || second === '') {
+      return -1;
+    }
+    const firstNumbers = first.split(/[\.-]/);
+    const secondNumbers = second.split(/[\.-]/);
+    const length = Math.max(firstNumbers.length, secondNumbers.length);
+    
+    for (let i = 0; i < length; i++) {
+      const firstNum = parseInt(firstNumbers[i] || '0');
+      const secondNum = parseInt(secondNumbers[i] || '0');
+      
+      if (firstNum > secondNum) return 1;
+      if (firstNum < secondNum) return -1;
+    }
+    return 0;
+  },
+ 
+  isSingleLine(string: string): boolean {
+    return String(string).trim().indexOf("\n") === -1;
+  },
+ 
+  arrayToCSV(array: Array<Record<string, any>>): string {
+    return array.map(item =>
+      Object.values(item).join(',')
+    ).join('\n');
+  },
+ 
+  getFileFromPath(path: string): string {
+    if (!path || typeof path !== 'string') {
+      return '';
+    }
+    return path.replace(/^.*[\/]/, '');
+  },
+ 
+  getPath(path: string): string {
+    if (!path || typeof path !== 'string' || path[0] !== '/') {
+      return '';
+    }
+    const lastSlash = path.lastIndexOf('/');
+    return lastSlash !== 0 ? path.substr(0, lastSlash) : '/';
+  },
+ 
+  getFormattedStringFromArray(array: string[], endSeparator: string = 'and'): string {
+    if (array.length === 0) return '';
+    if (array.length === 1) return array[0];
+    
+    const lastElement = array[array.length - 1];
+    const otherElements = array.slice(0, -1);
+    
+    return `${otherElements.join(', ')} ${endSeparator} ${lastElement}`;
+  },
+ 
+  pluralize(count: number, singular: string, plural?: string): string {
+    const _plural = plural || `${singular}s`; // Simple pluralization if not provided
+    return count > 1 ? _plural : singular;
+  },
+ 
+  htmlEntities(string: string): string {
+    if (typeof string !== 'string') return "";
+    const div = document.createElement('div');
+    div.textContent = string;
+    return div.innerHTML;
+  },
+ 
+  escapeRegExp(str: string): string {
+    return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+  },
+ 
+  getRandomString(len: number, allowed?: string): string {
+    if (len <= 0) {
+      throw new Error('len should be defined and more than 0');
+    }
+    
+    const chars = allowed || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    return Array.from({ length: len }, () =>
+      chars.charAt(Math.floor(Math.random() * chars.length))
+    ).join('');
+  },
+ 
+  upperUnderscoreToText(string: string): string {
+    if (typeof string !== 'string') {
+      return '';
+    }
+    return string
+      .split('_')
+      .map(word => word.toLowerCase().replace(/^\w/, c => c.toUpperCase()))
+      .join(' ');
+  },
+ 
+  unicodeEscape(string: string, regexp: RegExp = /[\s\S]/g): string {
+    return string.replace(regexp, (escape) =>
+      '\\u' + ('0000' + escape.charCodeAt(0).toString(16)).slice(-4)
+    );
+  }
+};
+ 
+export default stringUtilsObj;
\ No newline at end of file
diff --git a/ambari-web/latest/src/Utils/Utility.ts b/ambari-web/latest/src/Utils/Utility.ts
index 1dc0bb16c4..6786ae65e5 100644
--- a/ambari-web/latest/src/Utils/Utility.ts
+++ b/ambari-web/latest/src/Utils/Utility.ts
@@ -15,6 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+import { ReactNode } from "react";
 import { normalizeName } from "../screens/Hosts/helpers";
 import _, { startCase, get, has, isEmpty } from "lodash";
 import { messages } from "../screens/messages";
@@ -48,7 +50,6 @@ import DOMPurify from "isomorphic-dompurify";
 import parse from 'html-react-parser';
 import { t } from "i18next";
 import { HostsApi } from "../api/hostsApi";
-import { JSX } from "react";
 
 export const padNumber = (num: number) => (num < 10 ? `0${num}` : num);
 const components: any = {
@@ -1508,7 +1509,7 @@ export const initialUpgradeMethods = [
     isCheckComplete: false,
     isCheckRequestInProgress: false,
     precheckResultsMessage: "",
-    preCheckResultsModalContent: null as JSX.Element | null,
+    preCheckResultsModalContent: null as ReactNode,
     precheckResultsTitle: "",
     action: "",
     isWizardRestricted: false,
@@ -1529,7 +1530,7 @@ export const initialUpgradeMethods = [
     isCheckComplete: false,
     isCheckRequestInProgress: false,
     precheckResultsMessage: "",
-    preCheckResultsModalContent: null as JSX.Element | null,
+    preCheckResultsModalContent: null as ReactNode,
     precheckResultsTitle: "",
     action: "",
     isWizardRestricted: false,
@@ -1547,9 +1548,554 @@ export const initialUpgradeMethods = [
     isCheckComplete: false,
     isCheckRequestInProgress: false,
     precheckResultsMessage: "",
-    preCheckResultsModalContent: null as JSX.Element | null,
+    preCheckResultsModalContent: null as ReactNode,
     precheckResultsTitle: "",
     action: "",
     cantBeStarted: true,
   },
 ];
+
+export const createFallbackWidgetsForService = (
+  serviceName: string,
+  userName: string,
+) => {
+  const baseWidgets = [];
+
+  // Service-specific widget configurations
+  switch (serviceName.toUpperCase()) {
+    case "AMBARI_METRICS":
+      baseWidgets.push(
+        // Master Average Load
+        {
+          WidgetInfo: {
+            id: "service-metrics-ambari-metrics-master-average-load",
+            widget_name: "Average load",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "AverageLoad",
+                service_name: "AMBARI_METRICS",
+                component_name: "METRICS_COLLECTOR",
+                metric_path: "metrics/hbase/master/AverageLoad",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Average Load",
+                value: "${AverageLoad}",
+              },
+            ]),
+            properties: JSON.stringify({}),
+            scope: "USER",
+            author: userName,
+            description: "HBase master average load",
+          },
+        },
+        // RegionServer Regions
+        {
+          WidgetInfo: {
+            id: "service-metrics-ambari-metrics-region-server-regions",
+            widget_name: "Number of Regions",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "regions",
+                service_name: "AMBARI_METRICS",
+                component_name: "METRICS_COLLECTOR",
+                metric_path: "metrics/hbase/regionserver/regions",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Regions",
+                value: "${regions}",
+              },
+            ]),
+            properties: JSON.stringify({}),
+            scope: "USER",
+            author: userName,
+            description: "HBase RegionServer regions",
+          },
+        },
+        // RegionServer Store Files
+        {
+          WidgetInfo: {
+            id: "service-metrics-ambari-metrics-region-server-store-files",
+            widget_name: "Number of StoreFiles",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "storefiles",
+                service_name: "AMBARI_METRICS",
+                component_name: "METRICS_COLLECTOR",
+                metric_path: "metrics/hbase/regionserver/storefiles",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "StoreFiles",
+                value: "${storefiles}",
+              },
+            ]),
+            properties: JSON.stringify({}),
+            scope: "USER",
+            author: userName,
+            description: "HBase RegionServer store files",
+          },
+        },
+        // RegionServer Requests
+        {
+          WidgetInfo: {
+            id: "service-metrics-ambari-metrics-region-server-requests",
+            widget_name: "Total Request Count",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "requests._rate",
+                service_name: "AMBARI_METRICS",
+                component_name: "METRICS_COLLECTOR",
+                metric_path: "metrics/hbase/regionserver/requests._rate",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Request Rate",
+                value: "${requests._rate}",
+              },
+            ]),
+            properties: JSON.stringify({}),
+            scope: "USER",
+            author: userName,
+            description: "HBase RegionServer requests",
+          },
+        },
+        // RegionServer Block Cache Hit Percent
+        {
+          WidgetInfo: {
+            id: "service-metrics-ambari-metrics-region-server-block-cache-hit-percent",
+            widget_name: "Block Cache Hit Percent",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "blockCacheHitPercent",
+                service_name: "AMBARI_METRICS",
+                component_name: "METRICS_COLLECTOR",
+                metric_path: "metrics/hbase/regionserver/blockCacheHitPercent",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Block Cache Hit %",
+                value: "${blockCacheHitPercent}",
+              },
+            ]),
+            properties: JSON.stringify({}),
+            scope: "USER",
+            author: userName,
+            description: "HBase RegionServer block cache hit percent",
+          },
+        },
+        // RegionServer Compaction Queue Size
+        {
+          WidgetInfo: {
+            id: "service-metrics-ambari-metrics-region-server-compaction-queue-size",
+            widget_name: "Compaction Queue Size",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "compactionQueueSize",
+                service_name: "AMBARI_METRICS",
+                component_name: "METRICS_COLLECTOR",
+                metric_path: "metrics/hbase/regionserver/compactionQueueSize",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Compaction Queue",
+                value: "${compactionQueueSize}",
+              },
+            ]),
+            properties: JSON.stringify({}),
+            scope: "USER",
+            author: userName,
+            description: "HBase RegionServer compaction queue size",
+          },
+        },
+      );
+      break;
+
+    case "HDFS":
+      baseWidgets.push(
+        // NameNode GC count
+        {
+          WidgetInfo: {
+            id: "hdfs-namenode-gc-count",
+            widget_name: "NameNode GC count",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "jvm.JvmMetrics.GcCount._rate",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/jvm/gcCount._rate",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+              {
+                name: "jvm.JvmMetrics.GcCountG1 Old Generation._rate",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/jvm/GcCountG1 Old Generation._rate",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "GC total count",
+                value: "${jvm.JvmMetrics.GcCount._rate}",
+              },
+              {
+                name: "GC count of type major collection",
+                value: "${jvm.JvmMetrics.GcCountG1 Old Generation._rate}",
+              },
+            ]),
+            properties: JSON.stringify({
+              graph_type: "LINE",
+              time_range: "1",
+            }),
+            scope: "USER",
+            author: userName,
+            description:
+              "Count of total garbage collections and count of major type garbage collections of the JVM.",
+          },
+        },
+        // NameNode GC time
+        {
+          WidgetInfo: {
+            id: "hdfs-namenode-gc-time",
+            widget_name: "NameNode GC time",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "jvm.JvmMetrics.GcTimeMillisG1 Old Generation._rate",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/jvm/GcTimeMillisG1 Old Generation._rate",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "GC time in major collection",
+                value: "${jvm.JvmMetrics.GcTimeMillisG1 Old Generation._rate}",
+              },
+            ]),
+            properties: JSON.stringify({
+              display_unit: "ms",
+              graph_type: "LINE",
+              time_range: "1",
+            }),
+            scope: "USER",
+            author: userName,
+            description:
+              "Total time taken by major type garbage collections in milliseconds.",
+          },
+        },
+        // NN Connection Load
+        {
+          WidgetInfo: {
+            id: "hdfs-nn-connection-load",
+            widget_name: "NN Connection Load",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "rpc.rpc.client.NumOpenConnections",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/rpc/client/NumOpenConnections",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+              {
+                name: "rpc.rpc.datanode.NumOpenConnections",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/rpc/datanode/NumOpenConnections",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Open Client Connections",
+                value: "${rpc.rpc.client.NumOpenConnections}",
+              },
+              {
+                name: "Open Datanode Connections",
+                value: "${rpc.rpc.datanode.NumOpenConnections}",
+              },
+            ]),
+            properties: JSON.stringify({
+              graph_type: "LINE",
+              time_range: "1",
+            }),
+            scope: "USER",
+            author: userName,
+            description:
+              "Number of open RPC connections being managed by NameNode.",
+          },
+        },
+        // NameNode Heap
+        {
+          WidgetInfo: {
+            id: "hdfs-namenode-heap",
+            widget_name: "NameNode Heap",
+            widget_type: "GRAPH",
+            metrics: JSON.stringify([
+              {
+                name: "jvm.JvmMetrics.MemHeapCommittedM",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/jvm/memHeapCommittedM",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+              {
+                name: "jvm.JvmMetrics.MemHeapUsedM",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/jvm/memHeapUsedM",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "JVM heap committed",
+                value: "${jvm.JvmMetrics.MemHeapCommittedM}",
+              },
+              {
+                name: "JVM heap used",
+                value: "${jvm.JvmMetrics.MemHeapUsedM}",
+              },
+            ]),
+            properties: JSON.stringify({
+              display_unit: "MB",
+              graph_type: "LINE",
+              time_range: "1",
+            }),
+            scope: "USER",
+            author: userName,
+            description:
+              "Heap memory committed and Heap memory used with respect to time.",
+          },
+        },
+        // Failed disk volumes
+        {
+          WidgetInfo: {
+            id: "hdfs-failed-disk-volumes",
+            widget_name: "Failed disk volumes",
+            widget_type: "NUMBER",
+            metrics: JSON.stringify([
+              {
+                name: "FSDatasetState.org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.NumFailedVolumes._sum",
+                service_name: "HDFS",
+                component_name: "DATANODE",
+                metric_path: "metrics/dfs/datanode/NumFailedVolumes",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Failed disk volumes",
+                value:
+                  "${FSDatasetState.org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.NumFailedVolumes._sum}",
+              },
+            ]),
+            properties: JSON.stringify({
+              display_unit: "",
+            }),
+            scope: "USER",
+            author: userName,
+            description:
+              "Number of Failed disk volumes across all DataNodes. Its indicative of HDFS bad health.",
+          },
+        },
+        // Blocks With Corrupted Replicas
+        {
+          WidgetInfo: {
+            id: "hdfs-blocks-corrupted-replicas",
+            widget_name: "Blocks With Corrupted Replicas",
+            widget_type: "NUMBER",
+            metrics: JSON.stringify([
+              {
+                name: "Hadoop:service=NameNode,name=FSNamesystem.CorruptBlocks",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/dfs/FSNamesystem/CorruptBlocks",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Blocks With Corrupted Replicas",
+                value:
+                  "${Hadoop:service=NameNode,name=FSNamesystem.CorruptBlocks}",
+              },
+            ]),
+            properties: JSON.stringify({
+              warning_threshold: "0",
+              error_threshold: "50",
+            }),
+            scope: "USER",
+            author: userName,
+            description:
+              "Number represents data blocks with at least one corrupted replica (but not all of them). Its indicative of HDFS bad health.",
+          },
+        },
+        // Under Replicated Blocks
+        {
+          WidgetInfo: {
+            id: "hdfs-under-replicated-blocks",
+            widget_name: "Under Replicated Blocks",
+            widget_type: "NUMBER",
+            metrics: JSON.stringify([
+              {
+                name: "Hadoop:service=NameNode,name=FSNamesystem.UnderReplicatedBlocks",
+                service_name: "HDFS",
+                component_name: "NAMENODE",
+                metric_path: "metrics/dfs/FSNamesystem/UnderReplicatedBlocks",
+                host_component_criteria:
+                  "host_components/metrics/dfs/FSNamesystem/HAState=active",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "Under Replicated Blocks",
+                value:
+                  "${Hadoop:service=NameNode,name=FSNamesystem.UnderReplicatedBlocks}",
+              },
+            ]),
+            properties: JSON.stringify({
+              warning_threshold: "0",
+              error_threshold: "50",
+            }),
+            scope: "USER",
+            author: userName,
+            description:
+              "Number represents file blocks that does not meet the replication factor criteria. Its indicative of HDFS bad health.",
+          },
+        },
+        // HDFS Space Utilization
+        {
+          WidgetInfo: {
+            id: "hdfs-space-utilization",
+            widget_name: "HDFS Space Utilization",
+            widget_type: "GAUGE",
+            metrics: JSON.stringify([
+              {
+                name: "FSDatasetState.org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.Remaining",
+                service_name: "HDFS",
+                component_name: "DATANODE",
+                metric_path:
+                  "metrics/FSDatasetState/org/apache/hadoop/hdfs/server/datanode/fsdataset/impl/FsDatasetImpl/Remaining",
+              },
+              {
+                name: "FSDatasetState.org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.Capacity",
+                service_name: "HDFS",
+                component_name: "DATANODE",
+                metric_path: "metrics/dfs/datanode/Capacity",
+              },
+            ]),
+            values: JSON.stringify([
+              {
+                name: "HDFS Space Utilization",
+                value:
+                  "${(FSDatasetState.org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.Capacity - FSDatasetState.org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.Remaining)/FSDatasetState.org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.Capacity}",
+              },
+            ]),
+            properties: JSON.stringify({
+              warning_threshold: "0.75",
+              error_threshold: "0.9",
+            }),
+            scope: "USER",
+            author: userName,
+            description: "Percentage of available space used in the DFS.",
+          },
+        },
+      );
+      break;
+
+    case "YARN":
+      baseWidgets.push({
+        WidgetInfo: {
+          id: "yarn-resourcemanager-heap",
+          widget_name: "ResourceManager Heap",
+          widget_type: "GRAPH",
+          metrics: JSON.stringify([
+            {
+              name: "resourcemanager_heap",
+              service_name: "YARN",
+              component_name: "RESOURCEMANAGER",
+              metric_path: "metrics/jvm/HeapMemoryUsed",
+            },
+          ]),
+          values: JSON.stringify([]),
+          properties: JSON.stringify({}),
+          scope: "USER",
+          author: userName,
+          description: "ResourceManager Heap Memory",
+        },
+      });
+      break;
+
+    case "HBASE":
+      baseWidgets.push({
+        WidgetInfo: {
+          id: "hbase-master-heap",
+          widget_name: "HBase Master Heap",
+          widget_type: "GRAPH",
+          metrics: JSON.stringify([
+            {
+              name: "hbase_master_heap",
+              service_name: "HBASE",
+              component_name: "HBASE_MASTER",
+              metric_path: "metrics/jvm/HeapMemoryUsed",
+            },
+          ]),
+          values: JSON.stringify([]),
+          properties: JSON.stringify({}),
+          scope: "USER",
+          author: userName,
+          description: "HBase Master Heap Memory",
+        },
+      });
+      break;
+
+    default:
+      baseWidgets.push({
+        WidgetInfo: {
+          id: `${serviceName.toLowerCase()}-default-widget`,
+          widget_name: `${serviceName} Default Widget`,
+          widget_type: "GRAPH",
+          metrics: JSON.stringify([
+            {
+              name: "default_metric",
+              service_name: serviceName,
+              component_name: "DEFAULT_COMPONENT",
+              metric_path: "metrics/jvm/HeapMemoryUsed",
+            },
+          ]),
+          values: JSON.stringify([]),
+          properties: JSON.stringify({}),
+          scope: "USER",
+          author: userName,
+          description: `Default ${serviceName} widget`,
+        },
+      });
+  }
+
+  return baseWidgets;
+};
\ No newline at end of file
diff --git a/ambari-web/latest/src/Utils/adminViewRedirect.ts b/ambari-web/latest/src/Utils/adminViewRedirect.ts
new file mode 100644
index 0000000000..764a39600d
--- /dev/null
+++ b/ambari-web/latest/src/Utils/adminViewRedirect.ts
@@ -0,0 +1,50 @@
+/**
+ * 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 { ServiceApi } from '../api/serviceApi';
+
+export async function redirectToAdminView(adminPage = "") {
+//   if (!localStorage.getItem('app.isAuthorized.CLUSTER.UPGRADE_DOWNGRADE_STACK')) {
+//     window.location.replace('/#/login');
+//     return;
+//   }
+
+  try {
+    const data = await ServiceApi.getAmbariServerVersion();
+    const components = data?.components || [];
+
+    if (Array.isArray(components)) {
+      const mappedVersions = components
+        .filter(component => 
+          component?.RootServiceComponents?.component_name === 'AMBARI_SERVER' &&
+          component?.RootServiceComponents?.component_version
+        )
+        .map(component => component.RootServiceComponents.component_version);
+
+      if (mappedVersions.length > 0) {
+        const sortedVersions = mappedVersions.sort();
+        const latestVersion = sortedVersions[sortedVersions.length - 1].replace(/[^\d.-]/g, '');
+        const appRoot = window.location.origin;
+        window.location.replace(`${appRoot}/views/ADMIN_VIEW/${latestVersion}/INSTANCE/#/${adminPage}`);
+      }
+    }
+  } catch (error) {
+    console.error('Error getting admin version:', error);
+    window.location.replace('/#/main/views/index');
+  }
+}
\ No newline at end of file
diff --git a/ambari-web/latest/src/Utils/cacheUtils.ts b/ambari-web/latest/src/Utils/cacheUtils.ts
new file mode 100644
index 0000000000..63b3a6f0e1
--- /dev/null
+++ b/ambari-web/latest/src/Utils/cacheUtils.ts
@@ -0,0 +1,86 @@
+/**
+ * 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.
+ */
+
+interface CacheItem<T> {
+  data: T;
+  timestamp: number;
+  ttl: number;
+}
+
+class SimpleCache {
+  private cache = new Map<string, CacheItem<any>>();
+
+  set<T>(key: string, data: T, ttlMs: number = 30000): void {
+    this.cache.set(key, {
+      data,
+      timestamp: Date.now(),
+      ttl: ttlMs,
+    });
+  }
+
+  get<T>(key: string): T | null {
+    const item = this.cache.get(key);
+    if (!item) return null;
+
+    const now = Date.now();
+    if (now - item.timestamp > item.ttl) {
+      this.cache.delete(key);
+      return null;
+    }
+
+    return item.data;
+  }
+
+  has(key: string): boolean {
+    const item = this.cache.get(key);
+    if (!item) return false;
+
+    const now = Date.now();
+    if (now - item.timestamp > item.ttl) {
+      this.cache.delete(key);
+      return false;
+    }
+
+    return true;
+  }
+
+  clear(): void {
+    this.cache.clear();
+  }
+
+  delete(key: string): boolean {
+    return this.cache.delete(key);
+  }
+
+  // Clean expired entries
+  cleanup(): void {
+    const now = Date.now();
+    for (const [key, item] of this.cache.entries()) {
+      if (now - item.timestamp > item.ttl) {
+        this.cache.delete(key);
+      }
+    }
+  }
+}
+
+export const serviceCache = new SimpleCache();
+
+// Cleanup expired entries every 5 minutes
+setInterval(() => {
+  serviceCache.cleanup();
+}, 5 * 60 * 1000);
diff --git a/ambari-web/latest/src/Utils/clusterConfigUtils.ts b/ambari-web/latest/src/Utils/clusterConfigUtils.ts
new file mode 100644
index 0000000000..999ab24913
--- /dev/null
+++ b/ambari-web/latest/src/Utils/clusterConfigUtils.ts
@@ -0,0 +1,121 @@
+/**
+ * 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 ClusterApi from "../api/clusterApi";
+import ConfigsApi from "../api/configsApi";
+import { ambariApi } from "../api/config/axiosConfig";
+
+/**
+ * Safely update cluster-env configuration while preserving existing properties
+ * This prevents the auto-start settings from being accidentally reset
+ */
+export const safeUpdateClusterEnvConfig = async (
+  clusterName: string,
+  newProperties: Record<string, any>,
+  serviceConfigVersionNote?: string
+): Promise<any> => {
+  try {
+    
+    // Get current cluster configuration
+    const response = await ClusterApi.getCluster(clusterName);
+    const desiredConfigs = response?.Clusters?.desired_configs;
+
+    if (!desiredConfigs || !desiredConfigs["cluster-env"]) {
+      throw new Error('cluster-env configuration not found');
+    }
+
+    const clusterEnvTag = desiredConfigs["cluster-env"].tag;
+    
+    // Get current cluster-env configuration with all properties
+    const configUrl = `clusters/${clusterName}/configurations?type=cluster-env&tag=${clusterEnvTag}&fields=*`;
+    const configResponse = await ambariApi.request({
+      url: configUrl,
+      method: "GET",
+    });
+
+    if (!configResponse.data || !configResponse.data.items || configResponse.data.items.length === 0) {
+      throw new Error('Failed to get current cluster-env configuration');
+    }
+
+    const clusterEnvConfig = configResponse.data.items[0];
+    
+    // Get ALL existing properties from the current configuration
+    const existingProperties = clusterEnvConfig.properties || {};
+    
+    
+    // Create updated properties by merging existing properties with the new values
+    // This prevents data loss by preserving all existing configuration including recovery_enabled
+    const updatedProperties = {
+      ...existingProperties,
+      ...newProperties
+    };
+    
+
+    // Save the updated configuration using the proper service config API structure
+    const configData = {
+      Clusters: {
+        desired_config: {
+          type: "cluster-env",
+          tag: `version${Date.now()}`,
+          properties: updatedProperties, // Send ALL properties, not just the changed ones
+          service_config_version_note: serviceConfigVersionNote || "Updated cluster-env configuration"
+        }
+      }
+    };
+
+    const saveResponse = await ConfigsApi.saveConfigs(clusterName, configData);
+    
+    return saveResponse;
+  } catch (error) {
+    console.error("Error safely updating cluster-env config:", error);
+    throw error;
+  }
+};
+
+/**
+ * Get current cluster-env properties
+ */
+export const getClusterEnvProperties = async (clusterName: string): Promise<Record<string, any>> => {
+  try {
+    const response = await ClusterApi.getCluster(clusterName);
+    const desiredConfigs = response?.Clusters?.desired_configs;
+
+    if (!desiredConfigs || !desiredConfigs["cluster-env"]) {
+      throw new Error('cluster-env configuration not found');
+    }
+
+    const clusterEnvTag = desiredConfigs["cluster-env"].tag;
+    
+    // Get current cluster-env configuration
+    const configUrl = `clusters/${clusterName}/configurations?type=cluster-env&tag=${clusterEnvTag}&fields=*`;
+    const configResponse = await ambariApi.request({
+      url: configUrl,
+      method: "GET",
+    });
+
+    if (!configResponse.data || !configResponse.data.items || configResponse.data.items.length === 0) {
+      throw new Error('Failed to get current cluster-env configuration');
+    }
+
+    const clusterEnvConfig = configResponse.data.items[0];
+    return clusterEnvConfig.properties || {};
+  } catch (error) {
+    console.error("Error getting cluster-env properties:", error);
+    throw error;
+  }
+};
diff --git a/ambari-web/latest/src/Utils/configs.ts b/ambari-web/latest/src/Utils/configs.ts
new file mode 100644
index 0000000000..5f179ef961
--- /dev/null
+++ b/ambari-web/latest/src/Utils/configs.ts
@@ -0,0 +1,456 @@
+/**
+ * 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.
+ */
+
+// NnHaConfigInitializer.tsx
+// interfaces.ts
+export interface ConfigProperty {
+  name: string;
+  displayName: string;
+  value: string;
+  recommendedValue: string;
+  isVisible?: boolean;
+  isOverridable?: boolean;
+  filename?: string;
+}
+
+export interface ExtendedTopologyLocalDB {
+  installedServices: string[];
+  masterComponentHosts: MasterComponentHost[];
+  nameserviceId: string;
+}
+
+export interface MasterComponentHost {
+  component: string;
+  hostName: string;
+  isInstalled: boolean;
+}
+
+export interface NnHaConfigDependencies {
+  namespaceId: string;
+  serverConfigs: ServerConfig[];
+  isHadoopWindowsStack?: boolean;
+}
+
+export interface ServerConfig {
+  type: string;
+  properties: { [key: string]: string };
+}
+
+export interface Initializer {
+  type: any;
+  toReplace?: string;
+  modifier?: {
+    prefix?: string;
+    suffix?: string;
+    regex?: string;
+    delimiter?: string;
+  };
+  component?: any;
+  components?: any;
+  componentExists?: boolean;
+  portKey?: string;
+  port?: string;
+  asArray?: boolean;
+  isInstalled?: boolean;
+}
+// NnHaConfigInitializer.tsx
+
+// NnHaConfigInitializer.tsx
+
+class NnHaConfigInitializer {
+  static getRenameWithNamespaceConfig(toReplace: string): Initializer {
+    return {
+      type: 'rename',
+      toReplace: toReplace
+    };
+  }
+
+  static getNamespaceConfig(prefix: string = '', suffix: string = ''): Initializer {
+    return {
+      type: 'namespace',
+      modifier: {
+        prefix: prefix,
+        suffix: suffix
+      }
+    };
+  } 
+
+  static getReplaceNamespaceConfig(toReplace: string): Initializer {
+    return {
+      type: 'replace_namespace',
+      toReplace: toReplace
+    };
+  }
+
+  static getHostWithPortConfig(component: string, componentExists: boolean, prefix: string = '', suffix: string = '', port: string, portFromDependencies: boolean = false): Initializer {
+    return {
+      type: 'host_with_port',
+      component: component,
+      componentExists: componentExists,
+      modifier: {
+        prefix: prefix,
+        suffix: suffix
+      },
+      portKey: portFromDependencies ? port : undefined,
+      port: portFromDependencies ? undefined : port
+    };
+  }
+
+  static getHostsWithPortConfig(component: string | string[], prefix: string = '', suffix: string = '', delimiter: string = ',', port: string, portFromDependencies: boolean = false): Initializer {
+    return {
+      type: 'hosts_with_port',
+      component: component,
+      modifier: {
+        prefix: prefix,
+        suffix: suffix,
+        delimiter: delimiter
+      },
+      portKey: portFromDependencies ? port : undefined,
+      port: portFromDependencies ? undefined : port
+    };
+  }
+
+  static getComponentsHostsConfig(components: string | string[], asArray: boolean = false, isInstalled: boolean | undefined = undefined): Initializer {
+    return {
+      type: 'hosts_with_components',
+      components: Array.isArray(components) ? components : [components],
+      asArray: asArray,
+      isInstalled: isInstalled
+    };
+  }
+
+  static getSimpleComponentConfig(component: string, withModifier: boolean = true): Initializer {
+    return {
+      type: 'host_with_component',
+      component: component,
+      modifier: withModifier ? {
+        type: 'regexp',
+        regex: "([\\w|\\.]*)(?=:)"
+      } : undefined
+    } as any;
+  }
+
+  static getComponentConfigWithAffixes(component: string, prefix: string = '', suffix: string = ''): Initializer {
+    return {
+      type: 'host_with_component',
+      component: component,
+      modifier: {
+        type: 'regexp',
+        regex: ":\\/\\/" + "([\\w|\\.]*)(?=:)",
+        prefix: prefix,
+        suffix: suffix
+      } as any
+    };
+  }
+
+  static getHostsListComponentConfig(component: string, componentExists: boolean, delimiter: string = ','): Initializer {
+    return {
+      type: 'hosts_list_with_component',
+      component: component,
+      componentExists: componentExists,
+      modifier: {
+        delimiter: delimiter
+      }
+    };
+  }
+
+  uniqueInitializers: { [key: string]: (config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies) => ConfigProperty };
+
+  constructor() {
+    this.uniqueInitializers = {
+      'hbase.rootdir': this._initHbaseRootDir.bind(this),
+      'hawq_dfs_url': this._initHawqDfsUrl.bind(this),
+      'instance.volumes': this._initInstanceVolumes.bind(this),
+      'instance.volumes.replacements': this._initInstanceVolumesReplacements.bind(this),
+      'dfs.journalnode.edits.dir': this._initDfsJnEditsDir.bind(this),
+      'xasecure.audit.destination.hdfs.dir': this._initXasecureAuditDestinationHdfsDir.bind(this)
+    };
+  }
+
+  initialValue(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    
+    const initializers: { [key: string]: Initializer[] } = {
+      'dfs.ha.namenodes.${dfs.nameservices}': [NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')],
+      'dfs.namenode.rpc-address.${dfs.nameservices}.nn1': [
+        NnHaConfigInitializer.getHostWithPortConfig('NAMENODE', true, '', '', 'nnRpcPort', true),
+        NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')
+      ],
+      'dfs.namenode.rpc-address.${dfs.nameservices}.nn2': [
+        NnHaConfigInitializer.getHostWithPortConfig('NAMENODE', false, '', '', '8020', false),
+        NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')
+      ],
+      'dfs.namenode.http-address.${dfs.nameservices}.nn1': [
+        NnHaConfigInitializer.getHostWithPortConfig('NAMENODE', true, '', '', 'nnHttpPort', true),
+        NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')
+      ],
+      'dfs.namenode.http-address.${dfs.nameservices}.nn2': [
+        NnHaConfigInitializer.getHostWithPortConfig('NAMENODE', false, '', '', '50070', false),
+        NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')
+      ],
+      'dfs.namenode.https-address.${dfs.nameservices}.nn1': [
+        NnHaConfigInitializer.getHostWithPortConfig('NAMENODE', true, '', '', 'nnHttpsPort', true),
+        NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')
+      ],
+      'dfs.namenode.https-address.${dfs.nameservices}.nn2': [
+        NnHaConfigInitializer.getHostWithPortConfig('NAMENODE', false, '', '', '50470', false),
+        NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')
+      ],
+      'dfs.client.failover.proxy.provider.${dfs.nameservices}': [NnHaConfigInitializer.getRenameWithNamespaceConfig('${dfs.nameservices}')],
+      'dfs.nameservices': [NnHaConfigInitializer.getNamespaceConfig()],
+      'dfs.internal.nameservices': [NnHaConfigInitializer.getNamespaceConfig()],
+      'fs.defaultFS': [NnHaConfigInitializer.getNamespaceConfig('hdfs://')],
+      'dfs.namenode.shared.edits.dir': [
+        NnHaConfigInitializer.getHostsWithPortConfig('JOURNALNODE', 'qjournal://', '/${dfs.nameservices}', ';', '8485', false),
+        NnHaConfigInitializer.getReplaceNamespaceConfig('${dfs.nameservices}')
+      ],
+      'ha.zookeeper.quorum': [NnHaConfigInitializer.getHostsWithPortConfig('ZOOKEEPER_SERVER', '', '', ',', 'zkClientPort', true)]
+    };
+
+    const uniqueInitializer = {
+      'hbase.rootdir': this._initHbaseRootDir.bind(this),
+      'hawq_dfs_url': this._initHawqDfsUrl.bind(this),
+      'instance.volumes': this._initInstanceVolumes.bind(this),
+      'instance.volumes.replacements': this._initInstanceVolumesReplacements.bind(this),
+      'dfs.journalnode.edits.dir': this._initDfsJnEditsDir.bind(this),
+      'xasecure.audit.destination.hdfs.dir': this._initXasecureAuditDestinationHdfsDir.bind(this)
+    }[config.name];
+    if (uniqueInitializer) {
+      uniqueInitializer(config, localDB, dependencies);
+    }
+
+    const initializersForConfig = initializers[config.name];
+    if (initializersForConfig) {
+      initializersForConfig.forEach(initializer => {
+        switch (initializer.type) {
+          case 'rename':
+            this._initWithRename(config, localDB, dependencies, initializer);
+            break;
+          case 'namespace':
+            this._initAsNamespace(config, localDB, dependencies, initializer);
+            break;
+          case 'replace_namespace':
+            this._initWithNamespace(config, localDB, dependencies, initializer);
+            break;
+          case 'host_with_port':
+            this._initAsHostWithPort(config, localDB, dependencies, initializer);
+            break;
+          case 'hosts_with_port':
+            this._initAsHostsWithPort(config, localDB, dependencies, initializer);
+            break;
+          case 'hosts_with_components':
+            this._initAsHostsWithComponents(config, localDB, dependencies, initializer);
+            break;
+          case 'host_with_component':
+            this._initAsHostWithComponent(config, localDB, dependencies, initializer);
+            break;
+          case 'hosts_list_with_component':
+            this._initAsHostsListWithComponent(config, localDB, dependencies, initializer);
+            break;
+          default:
+            break;
+        }
+      });
+    }
+
+    config.isOverridable = false;
+    return config;
+  }
+
+  private _initWithRename(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies, initializer: Initializer): ConfigProperty {
+    console.log("Local DB is",localDB)
+    const replaceWith = dependencies.namespaceId;
+    const toReplace:any = initializer.toReplace;
+    if (!replaceWith) {
+      throw new Error('`dependencies.namespaceId` should be not empty string');
+    }
+    config.name = config.name.replace(toReplace, replaceWith);
+    config.displayName = config.displayName.replace(toReplace, replaceWith);
+    return config;
+  }
+
+  private _initAsNamespace(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies, initializer: any): ConfigProperty {
+    console.log("Local DB is",localDB)
+    const value = dependencies.namespaceId;
+    if (!value) {
+      throw new Error('`dependencies.namespaceId` should be not empty string');
+    }
+    config.value = initializer.modifier.prefix + value + initializer.modifier.suffix;
+    config.recommendedValue = config.value;
+    return config;
+  }
+
+  private _initWithNamespace(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies, initializer: Initializer): ConfigProperty {
+    console.log("Local DB is",localDB)
+    const replaceWith = dependencies.namespaceId;
+    const toReplace:any = initializer.toReplace;
+    if (!replaceWith) {
+      throw new Error('`dependencies.namespaceId` should be not empty string');
+    }
+    config.value = config.value.replace(toReplace, replaceWith);
+    config.recommendedValue = config.recommendedValue.replace(toReplace, replaceWith);
+    return config;
+  }
+
+  private _initAsHostWithPort(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: any, initializer: any): ConfigProperty {
+    const hostName = localDB.masterComponentHosts.find(host => host.component === initializer.component && host.isInstalled === initializer.componentExists)?.hostName;
+    const port = initializer.portKey ? dependencies[initializer.portKey] : initializer.port;
+    config.value = initializer.modifier.prefix + (hostName || '') + (port ? ':' + port : '') + initializer.modifier.suffix;
+    config.recommendedValue = config.value;
+    return config;
+  }
+
+  private _initAsHostsWithPort(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: any, initializer: any): ConfigProperty {
+    const hostNames = localDB.masterComponentHosts
+      .filter(host => initializer.component.includes(host.component) && (initializer.componentExists === undefined || host.isInstalled === initializer.componentExists))
+      .map(host => host.hostName);
+    const port = initializer.portKey ? dependencies[initializer.portKey] : initializer.port;
+    config.value = initializer.modifier.prefix + hostNames.map(host => host + (port ? ':' + port : '')).join(initializer.modifier.delimiter) + initializer.modifier.suffix;
+    config.recommendedValue = config.value;
+    return config;
+  }
+
+  private _initAsHostsWithComponents(config: any, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies, initializer: Initializer): ConfigProperty {
+    console.log("Dependencies is",dependencies);
+    const hostNames = localDB.masterComponentHosts
+      .filter(host => initializer.components.includes(host.component) && (initializer.isInstalled === undefined || host.isInstalled === initializer.isInstalled))
+      .map(host => host.hostName);
+    config.value = initializer.asArray ? hostNames : hostNames.join(',');
+    config.recommendedValue = config.value;
+    return config;
+  }
+
+  private _initAsHostWithComponent(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies, initializer: any): ConfigProperty {
+    console.log("Dependencies is",dependencies);
+    const component = localDB.masterComponentHosts.find(host => host.component === initializer.component);
+    if (!component) {
+      return config;
+    }
+    if (initializer.modifier) {
+      const replaceWith = initializer.modifier.prefix + component.hostName + initializer.modifier.suffix;
+      config.value = config.value.replace(initializer.modifier.regex, replaceWith);
+      config.recommendedValue = config.recommendedValue.replace(initializer.modifier.regex, replaceWith);
+    } else {
+      config.value = component.hostName;
+      config.recommendedValue = component.hostName;
+    }
+    return config;
+  }
+
+  private _initAsHostsListWithComponent(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies, initializer: any): ConfigProperty {
+    console.log("Dependencies is",dependencies);
+    const hostNames = localDB.masterComponentHosts
+      .filter(host => host.component === initializer.component && host.isInstalled === initializer.componentExists)
+      .map(host => host.hostName)
+      .join(initializer.modifier.delimiter);
+    config.value = hostNames;
+    config.recommendedValue = hostNames;
+    return config;
+  }
+
+  private _initHbaseRootDir(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    const fileName = config.filename;
+    if (fileName === 'hbase-site') {
+      return this._initHbaseRootDirForHbase(config, localDB, dependencies);
+    }
+    if (fileName === 'ams-hbase-site') {
+      return this._initHbaseRootDirForAMS(config, localDB, dependencies);
+    }
+    return config;
+  }
+
+  private _initHbaseRootDirForHbase(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    if (localDB.installedServices.includes('HBASE')) {
+      const value = dependencies.serverConfigs.find(config => config.type === 'hbase-site')?.properties['hbase.rootdir'].replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
+      config.value = value || '';
+      config.recommendedValue = value || '';
+    }
+    return config;
+  }
+
+  private _initHbaseRootDirForAMS(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    if (localDB.installedServices.includes('AMBARI_METRICS')) {
+      const value = dependencies.serverConfigs.find(config => config.type === 'ams-hbase-site')?.properties['hbase.rootdir'];
+      const currentNameNodeHost = localDB.masterComponentHosts.find(host => host.component === 'NAMENODE' && host.isInstalled)?.hostName;
+      if (value && value.includes('hdfs://' + currentNameNodeHost)) {
+        config.value = value.replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
+        config.recommendedValue = config.value;
+      }
+      else{
+        config.value=value as any,
+        config.recommendedValue=value as any
+      }
+    }
+    return config;
+  }
+
+  private _initHawqDfsUrl(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    if (localDB.installedServices.includes('HAWQ')) {
+      const value = dependencies.serverConfigs.find(config => config.type === 'hawq-site')?.properties['hawq_dfs_url'].replace(/(^.*:[0-9]+)(?=\/)/, dependencies.namespaceId);
+      config.value = value || '';
+      config.recommendedValue = value || '';
+    }
+    return config;
+  }
+
+  private _initInstanceVolumes(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    if (localDB.installedServices.includes('ACCUMULO')) {
+      const oldValue = dependencies.serverConfigs.find(config => config.type === 'accumulo-site')?.properties['instance.volumes'];
+      const value = oldValue?.replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
+      config.value = value || '';
+      config.recommendedValue = value || '';
+    }
+    return config;
+  }
+
+  private _initInstanceVolumesReplacements(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    if (localDB.installedServices.includes('ACCUMULO')) {
+      const oldValue = dependencies.serverConfigs.find(config => config.type === 'accumulo-site')?.properties['instance.volumes'];
+      const value = oldValue?.replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
+      const replacements = oldValue + " " + value;
+      config.value = replacements || '';
+      config.recommendedValue = replacements || '';
+    }
+    return config;
+  }
+
+  private _initDfsJnEditsDir(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    console.log("Dependencies is",dependencies,localDB);
+    // if (localDB.installedServices.includes('HDFS')) {
+    //   const value = dependencies.serverConfigs.find(config => config.type === 'hdfs-site')?.properties['dfs.journalnode.edits.dir'];
+    //   config.value = value || '';
+    //   config.recommendedValue = value || '';
+    // }
+    return config;
+  }
+
+  private _initXasecureAuditDestinationHdfsDir(config: ConfigProperty, localDB: ExtendedTopologyLocalDB, dependencies: NnHaConfigDependencies): ConfigProperty {
+    if (localDB.installedServices.includes('RANGER')) {
+      const oldValue = dependencies.serverConfigs.find(config => config.type === 'ranger-env')?.properties['xasecure.audit.destination.hdfs.dir'];
+      const valueArray = oldValue?.split('/');
+      if (valueArray && valueArray.length > 2) {
+        valueArray[2] = dependencies.namespaceId;
+        const newValue = valueArray.join('/');
+        config.value = newValue;
+        config.recommendedValue = newValue;
+      }
+    }
+    return config;
+  }
+}
+
+export default NnHaConfigInitializer;
\ No newline at end of file
diff --git a/ambari-web/latest/src/Utils/credentialsUtils.ts b/ambari-web/latest/src/Utils/credentialsUtils.ts
new file mode 100644
index 0000000000..a0c9b08770
--- /dev/null
+++ b/ambari-web/latest/src/Utils/credentialsUtils.ts
@@ -0,0 +1,153 @@
+/**
+ * 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 { find, map } from "lodash";
+import CredentialsApi from "../api/credentialsApi";
+
+const credentialsUtils = {
+  STORE_TYPES: {
+    TEMPORARY: "temporary",
+    PERSISTENT: "persisted",
+    PERSISTENT_KEY: "persistent",
+    TEMPORARY_KEY: "temporary",
+    PERSISTENT_PATH: "storage.persistent",
+    TEMPORARY_PATH: "storage.temporary",
+  },
+  ALIAS: {
+    KDC_CREDENTIALS: "kdc.admin.credential",
+  },
+  createCredentials: async function (
+    clusterName: string,
+    alias: string,
+    resource: string
+  ) {
+    return await CredentialsApi.createCredentials(clusterName, alias, {
+      resource,
+    });
+  },
+  getCredential: async function (
+    clusterName: string,
+    alias: string,
+    successCallback: any,
+    errorCallback: any
+  ) {
+    try {
+      const data = await CredentialsApi.getCredentials(clusterName, alias);
+      if (successCallback) {
+        successCallback(data);
+      }
+    } catch {
+      errorCallback();
+    }
+  },
+  updateCredentials: async function (
+    clusterName: string,
+    alias: string,
+    resource: string
+  ) {
+    return await CredentialsApi.updateCredentials(clusterName, alias, {
+      resource,
+    });
+  },
+  createOrUpdateCredentials: async function (
+    clusterName: string,
+    alias: string,
+    resource: string
+  ) {
+    const self = this;
+    self.getCredential(
+      clusterName,
+      alias,
+      async () => {
+        await self.updateCredentials(clusterName, alias, resource);
+        var status = arguments[1];
+        var result = arguments[2];
+        if (status === "success") {
+          return result;
+        }
+      },
+      async () => {
+        await self.createCredentials(clusterName, alias, resource);
+        var status = arguments[1];
+        var result = arguments[2];
+        if (status === "success") {
+          return result;
+        }
+      }
+    );
+  },
+  credentials: async function (clusterName: string, callback: Function) {
+    const data = await CredentialsApi.listCredentials(clusterName);
+    callback(map(data?.items, "Credential"));
+  },
+  removeCredentials: async function (clusterName: string, alias: string) {
+    return await CredentialsApi.deleteCredentials(clusterName, alias);
+  },
+  storageInfo: async function (clusterName: string, callback: Function) {
+    const json = await CredentialsApi.credentialsStoreInfo(clusterName);
+    if (json.Clusters) {
+      const storage = json?.Clusters?.credential_store_properties ?? {};
+      let storeTypesObject: any = {};
+      storeTypesObject[this.STORE_TYPES.PERSISTENT_KEY] =
+        storage[this.STORE_TYPES.PERSISTENT_PATH] === "true";
+      storeTypesObject[this.STORE_TYPES.TEMPORARY_KEY] =
+        storage[this.STORE_TYPES.TEMPORARY_PATH] === "true";
+      callback(storeTypesObject);
+    } else {
+      callback(null);
+    }
+  },
+  isStorePersisted: function (clusterName: string) {
+    return this.storeTypeStatus(clusterName, this.STORE_TYPES.PERSISTENT_KEY);
+  },
+  isStoreTemporary: function (clusterName: string) {
+    return this.storeTypeStatus(clusterName, this.STORE_TYPES.TEMPORARY_KEY);
+  },
+  storeTypeStatus: function (clusterName: string, type: string) {
+    this.storageInfo(clusterName, function (storage: any) {
+      return storage?.[type];
+    });
+  },
+  createCredentialResource: function (
+    principal: string,
+    key: string,
+    type: string
+  ) {
+    return {
+      principal: principal,
+      key: key,
+      type: type,
+    };
+  },
+  isKDCCredentialsPersisted: function (credentials: any) {
+    var kdcCredentials = find(credentials, [
+      "alias",
+      this.ALIAS.KDC_CREDENTIALS,
+    ]);
+    if (kdcCredentials) {
+      const type =
+        kdcCredentials.type !== undefined
+          ? kdcCredentials.type
+          : this.STORE_TYPES.TEMPORARY;
+      return type === this.STORE_TYPES.PERSISTENT;
+    }
+    return false;
+  },
+};
+
+export default credentialsUtils;
diff --git a/ambari-web/latest/src/screens/ClusterWizard/Step7/DirectoriesTab.tsx b/ambari-web/latest/src/Utils/jvmFormatUtils.ts
similarity index 70%
rename from ambari-web/latest/src/screens/ClusterWizard/Step7/DirectoriesTab.tsx
rename to ambari-web/latest/src/Utils/jvmFormatUtils.ts
index b5dd7572a8..b6c741b0c2 100644
--- a/ambari-web/latest/src/screens/ClusterWizard/Step7/DirectoriesTab.tsx
+++ b/ambari-web/latest/src/Utils/jvmFormatUtils.ts
@@ -16,12 +16,14 @@
  * limitations under the License.
  */
 
-import { Card } from "react-bootstrap";
+export const formatParamsForDisplay = (_value: string, _displayType?: string): string => {
+  return "In Progress";
+}
 
-export default function DirectoriesTab() {
-  return (
-    <Card>
-      <h5 className="p-4">Directories Tab</h5>
-    </Card>
-  );
+export const formatParamsForSave = (_value: string): string => {
+  return "In Progress";
+}
+
+export const shouldUseMultilineFormatting = (_value: string, _displayType?: string): string => {
+  return "In Progress";
 }
\ No newline at end of file
diff --git a/ambari-web/latest/src/Utils/sslProtocolUtils.ts b/ambari-web/latest/src/Utils/sslProtocolUtils.ts
new file mode 100644
index 0000000000..a34d89c991
--- /dev/null
+++ b/ambari-web/latest/src/Utils/sslProtocolUtils.ts
@@ -0,0 +1,287 @@
+/**
+ * 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.
+ */
+
+/**
+ * SSL Protocol Utilities - Following Ember.js setProtocol patterns
+ * Implements sophisticated SSL detection logic for different services and components
+ */
+
+interface ProtocolConfig {
+  type?: string;
+  checks?: Array<{
+    site: string;
+    property: string;
+    desired: string;
+  }>;
+}
+
+interface ConfigProperty {
+  type: string;
+  properties: { [key: string]: string };
+}
+
+/**
+ * Services that support HTTPS with specific SSL configurations
+ * Following Ember.js servicesSupportsHttps pattern
+ */
+export const SERVICES_SUPPORTS_HTTPS = ["HDFS", "HBASE", "PINOT"];
+
+/**
+ * Check if desired condition is met for SSL configuration
+ * Following Ember.js meetDesired pattern
+ */
+const meetDesired = (
+  configProperties: ConfigProperty[],
+  configType: string,
+  property: string,
+  desiredState: string
+): boolean => {
+  const currentConfig = configProperties.find(config => config.type === configType);
+  
+  if (!currentConfig) {
+    return false;
+  }
+  
+  const currentPropertyValue = currentConfig.properties[property];
+  
+  if ('NOT_EXIST' === desiredState) {
+    return currentPropertyValue == null || currentPropertyValue === undefined;
+  }
+  if ('EXIST' === desiredState) {
+    return currentPropertyValue != null && currentPropertyValue !== undefined;
+  }
+  return desiredState === currentPropertyValue;
+};
+
+/**
+ * Reverse protocol type for fallback logic
+ * Following Ember.js reverseType pattern
+ */
+const reverseType = (type: string): string => {
+  if ('https' === type) {
+    return 'http';
+  }
+  if ('http' === type) {
+    return 'https';
+  }
+  return '';
+};
+
+/**
+ * Main protocol determination function following Ember.js setProtocol logic
+ * Determines protocol based on service configuration and SSL settings
+ */
+export const setProtocol = (
+  configProperties: ConfigProperty[],
+  protocolConfig?: ProtocolConfig
+): string => {
+  // Check global Hadoop SSL setting
+  let hadoopSslEnabled = false;
+  
+  if (configProperties && configProperties.length > 0) {
+    const hdfsSite = configProperties.find(config => config.type === 'hdfs-site');
+    hadoopSslEnabled = !!(hdfsSite && 
+                         hdfsSite.properties && 
+                         hdfsSite.properties['dfs.http.policy'] === 'HTTPS_ONLY');
+  }
+
+  // If no protocol config, use global Hadoop SSL setting
+  if (!protocolConfig) {
+    return hadoopSslEnabled ? 'https' : 'http';
+  }
+
+  const protocolType = protocolConfig.type;
+
+  // Explicit protocol type overrides
+  if ('HTTPS_ONLY' === protocolType) {
+    return 'https';
+  }
+  if ('HTTP_ONLY' === protocolType) {
+    return 'http';
+  }
+
+  // If no checks defined, use global Hadoop SSL setting
+  const checks = protocolConfig.checks;
+  if (!checks) {
+    return hadoopSslEnabled ? 'https' : 'http';
+  }
+
+  // Process protocol checks
+  const protocolTypeLower = protocolType?.toLowerCase() || 'http';
+  let failedChecks = 0;
+  
+  checks.forEach(check => {
+    const configType = check.site;
+    const property = check.property;
+    const desiredState = check.desired;
+    const checkMet = meetDesired(configProperties, configType, property, desiredState);
+    
+    if (!checkMet) {
+      failedChecks++;
+    }
+  });
+
+  // If any checks failed, reverse the protocol type
+  return failedChecks > 0 ? reverseType(protocolTypeLower) : protocolTypeLower;
+};
+
+/**
+ * Service-specific SSL configuration patterns
+ * Based on Ember.js quick_links.js FIXTURES
+ */
+export const SERVICE_SSL_CONFIGS = {
+  HDFS: {
+    supportsHttps: true,
+    httpConfig: 'dfs.namenode.http-address',
+    httpsConfig: 'dfs.namenode.https-address',
+    site: 'hdfs-site',
+    defaultHttpPort: 50070,
+    defaultHttpsPort: 50470
+  },
+  YARN: {
+    supportsHttps: true,
+    httpConfig: 'yarn.resourcemanager.webapp.address',
+    httpsConfig: 'yarn.resourcemanager.webapp.https.address',
+    site: 'yarn-site',
+    defaultHttpPort: 8088,
+    defaultHttpsPort: 8090
+  },
+  MAPREDUCE2: {
+    supportsHttps: true,
+    httpConfig: 'mapreduce.jobhistory.webapp.address',
+    httpsConfig: 'mapreduce.jobhistory.webapp.https.address',
+    site: 'mapred-site',
+    defaultHttpPort: 19888,
+    defaultHttpsPort: 19888
+  },
+  HBASE: {
+    supportsHttps: false,
+    httpConfig: 'hbase.master.info.port',
+    site: 'hbase-site',
+    defaultHttpPort: 60010
+  },
+  RANGER: {
+    supportsHttps: true,
+    httpConfig: 'http.service.port',
+    httpsConfig: 'https.service.port',
+    site: 'ranger-site',
+    defaultHttpPort: 6080,
+    defaultHttpsPort: 6182,
+    specialExternalUrl: 'policymgr_external_url', // Special Ranger handling
+    externalUrlSite: 'admin-properties'
+  },
+  ATLAS: {
+    supportsHttps: true,
+    httpConfig: 'atlas.server.http.port',
+    httpsConfig: 'atlas.server.https.port',
+    site: 'application-properties',
+    defaultHttpPort: 21000,
+    defaultHttpsPort: 21443
+  },
+  AMBARI_METRICS: {
+    supportsHttps: false,
+    httpConfig: 'port',
+    site: 'ams-grafana-ini',
+    defaultHttpPort: 3000,
+    defaultHttpsPort: 3000
+  },
+  ACCUMULO: {
+    supportsHttps: true,
+    httpConfig: 'monitor.port.client',
+    httpsConfig: 'monitor.port.client', // Same property
+    site: 'accumulo-site',
+    defaultHttpPort: 50095,
+    defaultHttpsPort: 50095
+  },
+  LOGSEARCH: {
+    supportsHttps: true,
+    httpConfig: 'logsearch_ui_port',
+    httpsConfig: 'logsearch_ui_port', // Same property
+    site: 'logsearch-env',
+    defaultHttpPort: 61888,
+    defaultHttpsPort: 61888
+  },
+  STORM: {
+    supportsHttps: false,
+    httpConfig: 'ui.port',
+    site: 'storm-site',
+    defaultHttpPort: 8744
+  },
+  FALCON: {
+    supportsHttps: false,
+    httpConfig: 'falcon_port',
+    site: 'falcon-env',
+    defaultHttpPort: 15000
+  },
+  SPARK: {
+    supportsHttps: false,
+    httpConfig: 'spark.history.ui.port',
+    site: 'spark-defaults',
+    defaultHttpPort: 18080
+  },
+  PINOT: {
+    supportsHttps: true,
+    httpConfig: 'controller.access.protocols.http.port',
+    httpsConfig: 'controller.access.protocols.https.port',
+    site: 'pinot-controller-conf',
+    defaultHttpPort: 9000,
+    defaultHttpsPort: 8444,
+    sslCheckProperty: 'enable.tls',
+    sslCheckSite: 'pinot-common-conf'
+  }
+};
+
+/**
+ * Get SSL configuration for a specific service
+ */
+export const getServiceSSLConfig = (serviceName: string) => {
+  return SERVICE_SSL_CONFIGS[serviceName as keyof typeof SERVICE_SSL_CONFIGS] || null;
+};
+
+/**
+ * Determine if service supports HTTPS
+ */
+export const serviceSupportsHttps = (serviceName: string): boolean => {
+  const config = getServiceSSLConfig(serviceName);
+  return config?.supportsHttps || false;
+};
+
+/**
+ * Get appropriate protocol for a service based on its configuration
+ * Following Ember.js service-specific protocol logic
+ */
+export const getServiceProtocol = (
+  serviceName: string,
+  configProperties: ConfigProperty[],
+  protocolConfig?: ProtocolConfig
+): string => {
+  const serviceConfig = getServiceSSLConfig(serviceName);
+  
+  if (!serviceConfig) {
+    // Fallback to global SSL detection
+    return setProtocol(configProperties, protocolConfig);
+  }
+
+  // If service doesn't support HTTPS, always return HTTP
+  if (!serviceConfig.supportsHttps) {
+    return 'http';
+  }
+
+  // Use Ember.js setProtocol logic for services that support HTTPS
+  return setProtocol(configProperties, protocolConfig);
+};
diff --git a/ambari-web/latest/src/Utils/unitConversionUtils.ts b/ambari-web/latest/src/Utils/unitConversionUtils.ts
new file mode 100644
index 0000000000..8fb3c2e5d1
--- /dev/null
+++ b/ambari-web/latest/src/Utils/unitConversionUtils.ts
@@ -0,0 +1,358 @@
+/**
+ * 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.
+ */
+export const convertMapTable = {
+  size: {
+    b: 1024,
+    kb: 1024,
+    mb: 1024,
+    gb: 1024,
+    tb: 1024,
+    pb: 1024
+  },
+  time: {
+    milliseconds: 1,
+    seconds: 1000,
+    minutes: 60,
+    hours: 60,
+    days: 24
+  },
+  percent: {
+    percent_int: {
+      int: 1,
+      percent: 1
+    },
+    percent_float: {
+      float: 1,
+      percent: 0.01
+    }
+  },
+  dimensionless: {
+    int: 1,
+    float: 1
+  }
+};
+
+// Unit label mapping for display
+export const unitLabelMap: Record<string, string> = {
+  percent: '%',
+  int: '',
+  float: '',
+  b: 'B',
+  kb: 'KB',
+  mb: 'MB',
+  gb: 'GB',
+  tb: 'TB',
+  pb: 'PB',
+  milliseconds: 'ms',
+  seconds: 's',
+  minutes: 'min',
+  hours: 'h',
+  days: 'd'
+};
+
+// Data type units that should not display units
+const DATA_TYPES = ['int', 'float'];
+
+/**
+ * Check if a unit is a data type (int/float)
+ */
+export function isDataType(unit: string): boolean {
+  return DATA_TYPES.includes(unit?.toLowerCase());
+}
+
+/**
+ * Get dimension table map for unit conversion
+ */
+function getUnitTable(unit: string, currentDimensionType?: string): Record<string, any> {
+  let unitType: string;
+  
+  if (currentDimensionType) {
+    unitType = currentDimensionType;
+  } else {
+    // Find the dimension type by looking for the unit in conversion tables
+    unitType = Object.keys(convertMapTable).find(item => {
+      const table = convertMapTable[item as keyof typeof convertMapTable];
+      return Object.keys(table).includes(unit?.toLowerCase());
+    }) || 'dimensionless';
+  }
+  
+  return convertMapTable[unitType as keyof typeof convertMapTable] || convertMapTable.dimensionless;
+}
+
+/**
+ * Convert single value between units
+ */
+function convertToSingleValue(value: number, fromUnit: string, toUnit: string, currentDimensionType?: string): number {
+  const convertTable = getUnitTable(fromUnit, currentDimensionType);
+  const units = Object.keys(convertTable);
+  const fromUnitIndex = units.indexOf(fromUnit.toLowerCase());
+  const toUnitIndex = units.indexOf(toUnit.toLowerCase());
+  
+  if (fromUnitIndex === -1) {
+    console.warn(`Invalid value unit type: ${fromUnit}`);
+    return value;
+  }
+  
+  if (toUnitIndex === -1) {
+    console.warn(`Invalid desired unit type: ${toUnit}`);
+    return value;
+  }
+  
+  if (fromUnitIndex === toUnitIndex) {
+    return value;
+  }
+  
+  const range = [fromUnitIndex + 1, toUnitIndex + 1];
+  const processedUnits = units.slice(...(range[0] < range[1] ? range : range.slice().reverse()));
+  
+  const factor = processedUnits.reduce((p, unit) => p * convertTable[unit], 1);
+  
+  if (range[0] < range[1]) {
+    value /= factor;
+  } else {
+    value *= factor;
+  }
+  
+  return Number.isInteger(value) ? value : parseFloat(value.toFixed(3));
+}
+
+/**
+ * Main conversion function - converts value between different unit types
+ */
+export function convertValue(
+  value: number | number[],
+  fromUnit: string | string[],
+  toUnit: string | string[],
+  isObjectOutput: boolean = false,
+  currentDimensionType?: string
+): number | Array<{value: number, type: string}> {
+  const valueIsArray = Array.isArray(value);
+  
+  if (!valueIsArray) {
+    value = +value;
+  }
+  
+  // If units are the same and no object output requested, return as is
+  if ((fromUnit === toUnit || !toUnit) && !isObjectOutput) {
+    return value as number;
+  }
+  
+  if (isNaN(value as number) && !valueIsArray) {
+    return 0;
+  }
+  
+  // Convert toUnit to array if it's a string
+  const toUnitArray = Array.isArray(toUnit) ? toUnit : toUnit.split(',');
+  
+  // Process multi unit format or object output
+  if (toUnitArray.length > 1 || isObjectOutput) {
+    let remainingValue = value as number;
+    return toUnitArray.map(unit => {
+      const convertedValue = Math.floor(convertToSingleValue(remainingValue, fromUnit as string, unit, currentDimensionType));
+      remainingValue -= convertToSingleValue(convertedValue, unit, fromUnit as string, currentDimensionType);
+      return {
+        value: convertedValue,
+        type: unit
+      };
+    });
+  } else {
+    // Single unit format
+    if (!valueIsArray) {
+      return convertToSingleValue(value as number, fromUnit as string, toUnitArray[0], currentDimensionType);
+    } else {
+      // Handle array input - sum all values after converting to target unit
+      if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'object' && value[0] !== null && 'value' in value[0]) {
+        const arrayValue = value as unknown as Array<{value: number, type: string}>;
+        return arrayValue
+          .map(item => convertToSingleValue(item.value, item.type, toUnitArray[0], currentDimensionType))
+          .reduce((sum, val) => sum + val, 0);
+      } else {
+        // Fallback for simple number arrays or invalid input
+        return 0;
+      }
+    }
+  }
+}
+
+/**
+ * Get unit label for display
+ */
+export function getUnitLabel(unit: string): string {
+  return unitLabelMap[unit?.toLowerCase()] || unit || '';
+}
+
+/**
+ * Check if unit should be displayed (hide for int/float)
+ */
+export function shouldDisplayUnit(unit: string): boolean {
+  return Boolean(unit) && !isDataType(unit) && unit.toLowerCase() !== 'dimensionless';
+}
+
+/**
+ * Get display unit label (empty for int/float)
+ */
+export function getDisplayUnitLabel(unit: string): string {
+  return shouldDisplayUnit(unit) ? getUnitLabel(unit) : '';
+}
+
+/**
+ * Get config unit information from property
+ */
+export function getConfigUnitInfo(property: any): {
+  configUnit: string;
+  widgetUnit: string;
+  dimensionType: string;
+  configType: string;
+} {
+  // Get config unit from property attributes
+  const configUnit = property?.propertyAttributes?.unit || property?.propertyAttributes?.type || 'int';
+  
+  // Get widget unit from widget definition or fall back to config unit
+  const widgetUnit = property?.widget?.units?.[0]?.['unit-name'] || 
+                     property?.widget?.units?.[0]?.unit || 
+                     configUnit;
+  
+  // Determine dimension type
+  let dimensionType = '';
+  if (['int', 'float'].includes(configUnit.toLowerCase()) && widgetUnit.toLowerCase() === 'percent') {
+    dimensionType = `percent.percent_${configUnit.toLowerCase()}`;
+  } else {
+    // Auto-detect dimension type
+    dimensionType = Object.keys(convertMapTable).find(type => {
+      const table = convertMapTable[type as keyof typeof convertMapTable];
+      return Object.keys(table).includes(widgetUnit.toLowerCase());
+    }) || 'dimensionless';
+  }
+  
+  return {
+    configUnit: configUnit.toLowerCase(),
+    widgetUnit: widgetUnit.toLowerCase(),
+    dimensionType,
+    configType: property?.propertyAttributes?.type || 'int'
+  };
+}
+
+/**
+ * Convert config value to widget value
+ */
+export function widgetValueByConfigAttributes(
+  value: number,
+  configUnit: string,
+  widgetUnit: string,
+  dimensionType?: string
+): number {
+  if (!value || configUnit === widgetUnit) return value;
+  return convertValue(value, configUnit, widgetUnit, false, dimensionType) as number;
+}
+
+/**
+ * Convert widget value back to config value
+ */
+export function configValueByWidget(
+  value: number,
+  widgetUnit: string,
+  configUnit: string,
+  configType: string,
+  dimensionType?: string
+): number {
+  if (!value || widgetUnit === configUnit) return value;
+  const converted = convertValue(value, widgetUnit, configUnit, false, dimensionType) as number;
+  return configType === 'int' ? Math.round(converted) : converted;
+}
+
+/**
+ * Format tick label for sliders (matches Ember formatTickLabel exactly)
+ */
+export function formatTickLabel(tick: number, unit: string, separator: string = ''): string {
+  if (!shouldDisplayUnit(unit)) {
+    return tick.toString();
+  }
+  
+  let valueLabel = tick;
+  let unitLabel = getUnitLabel(unit);
+  
+  // Handle size units with auto-scaling (matches Ember logic exactly)
+  const sizeUnits = ['B', 'KB', 'MB', 'GB', 'TB'];
+  const unitLabelIndex = sizeUnits.indexOf(unitLabel);
+  
+  if (unitLabelIndex > -1) {
+    let scaledTick = tick;
+    let scaledUnitIndex = unitLabelIndex;
+    
+
+    while (scaledTick >= 1024 && scaledUnitIndex < sizeUnits.length - 1) {
+      scaledTick /= 1024;
+      scaledUnitIndex++;
+    }
+    
+    unitLabel = sizeUnits[scaledUnitIndex];
+    valueLabel = parseFloat(scaledTick.toFixed(3));
+  }
+  
+  return valueLabel + separator + unitLabel;
+}
+
+/**
+ * Round number to 3 decimal places
+ */
+export function extraRound(value: number): number {
+  return parseFloat(value.toFixed(3));
+}
+
+/**
+ * Parse time interval from config value to appropriate time units (days, hours, minutes, seconds)
+ */
+export function parseTimeInterval(value: number, configUnit: string): {days: number, hours: number, minutes: number, seconds: number} {
+  // Convert to milliseconds first
+  const milliseconds = convertValue(value, configUnit, 'milliseconds') as number;
+  
+  const totalSeconds = Math.floor(milliseconds / 1000);
+  const days = Math.floor(totalSeconds / (24 * 60 * 60));
+  const hours = Math.floor((totalSeconds % (24 * 60 * 60)) / (60 * 60));
+  const minutes = Math.floor((totalSeconds % (60 * 60)) / 60);
+  const seconds = totalSeconds % 60;
+  
+  return { days, hours, minutes, seconds };
+}
+
+/**
+ * Compose time interval from time components back to config unit
+ */
+export function composeTimeInterval(days: number, hours: number, minutes: number, seconds: number, configUnit: string): number {
+  const totalMilliseconds = ((days * 24 * 60 * 60) + (hours * 60 * 60) + (minutes * 60) + seconds) * 1000;
+  return convertValue(totalMilliseconds, 'milliseconds', configUnit) as number;
+}
+
+/**
+ * Get parse function based on unit type
+ */
+export function getParseFunction(unitType: string): (value: string) => number {
+  return unitType === 'int' ? parseInt : parseFloat;
+}
+
+/**
+ * Check if widget unit is higher precision than config unit
+ */
+export function isWidgetUnitHigher(configUnit: string, widgetUnit: string): boolean {
+  const units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb'];
+  const configIndex = units.indexOf(configUnit.toLowerCase());
+  const widgetIndex = units.indexOf(widgetUnit.toLowerCase());
+  
+  if (configIndex === -1 || widgetIndex === -1) return false;
+  return widgetIndex > configIndex;
+}
diff --git a/ambari-web/latest/src/api/AssignMastersApi.ts b/ambari-web/latest/src/api/AssignMastersApi.ts
deleted file mode 100644
index aa3b246b3c..0000000000
--- a/ambari-web/latest/src/api/AssignMastersApi.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * 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 { ambariApi } from "./config/axiosConfig";
-
-const AssignMastersApi = {
-  getCpuInfo: async function (HOSTS: any) {
-    const hostsParams = HOSTS.join(",");
-    const url = `/hosts?Hosts/host_name.in(${hostsParams})&fields=Hosts/cpu_count,Hosts/disk_info,Hosts/total_mem,Hosts/ip,Hosts/os_type,Hosts/os_arch,Hosts/public_host_name&minimal_response=true`;
-    const response = await ambariApi.request({
-      url: url,
-      method: "GET",
-    });
-    return response;
-  },
-  postRecommendations: async function (
-    payload: any,
-    STACK: string,
-    VERSION: string
-  ) {
-    const url = `/stacks/${STACK}/versions/${VERSION}/recommendations`;
-    const response = await ambariApi.request({
-      url: url,
-      method: "POST",
-      data: payload,
-    });
-    return response.data;
-  },
-  postValidations: async function (
-    payload: any,
-    STACK: string,
-    VERSION: string
-  ) {
-    const url = `/stacks/${STACK}/versions/${VERSION}/validations`;
-    const response = await ambariApi.request({
-      url: url,
-      method: "POST",
-      data: payload,
-    });
-    return response.data;
-  },
-};
-export default AssignMastersApi;
diff --git a/ambari-web/latest/src/api/ActionsApi.ts b/ambari-web/latest/src/api/actionsApi.ts
similarity index 100%
rename from ambari-web/latest/src/api/ActionsApi.ts
rename to ambari-web/latest/src/api/actionsApi.ts
diff --git a/ambari-web/latest/src/api/adminApi.ts b/ambari-web/latest/src/api/adminApi.ts
new file mode 100644
index 0000000000..5aca8acf4f
--- /dev/null
+++ b/ambari-web/latest/src/api/adminApi.ts
@@ -0,0 +1,73 @@
+/**
+ * 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 { ambariApi } from "./config/axiosConfig";
+
+const AdminApi = {
+
+  getNnCheckPointStatus: async function (clusterName:string, hostName:string) {
+    const url = `/clusters/${clusterName}/hosts/${hostName}/host_components/NAMENODE`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getNnCheckPointStatuses: async function (clusterName:string, hostNames:string) {
+    const url = `/clusters/${clusterName}/host_components?HostRoles/component_name=NAMENODE&HostRoles/host_name.in(${hostNames})&fields=HostRoles/desired_state,metrics/dfs/namenode&minimal_response=true`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getJnCheckPointStatus:async function(clusterName:string, hostName:string){
+    const url = `/clusters/${clusterName}/hosts/${hostName}/host_components/JOURNALNODE?fields=metrics`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getSecurityStatus:async function(clusterName:string){
+    const url=`/clusters/${clusterName}?fields=Clusters/security_type`
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getSecurityType:async function(clusterName:string){
+    const url=`/clusters/${clusterName}/configurations/service_config_versions?service_name=KERBEROS&is_current=true`
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getKerberosSessionState:async function(clusterName:string){
+    const url=`/clusters/${clusterName}/services/KERBEROS?fields=Services/attributes/kdc_validation_result,Services/attributes/kdc_validation_failure_details`
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  }
+};
+
+export default AdminApi
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/assignMastersApi.ts b/ambari-web/latest/src/api/assignMastersApi.ts
new file mode 100644
index 0000000000..b07f944cd7
--- /dev/null
+++ b/ambari-web/latest/src/api/assignMastersApi.ts
@@ -0,0 +1,50 @@
+/**
+ * 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 { ambariApi } from "./config/axiosConfig";
+
+const AssignMastersApi = {
+    getCpuInfo: async function(HOSTS: any) {
+        const hostsParams = HOSTS.join(',');
+        const url = `/hosts?Hosts/host_name.in(${hostsParams})&fields=Hosts/cpu_count,Hosts/disk_info,Hosts/total_mem,Hosts/ip,Hosts/os_type,Hosts/os_arch,Hosts/public_host_name&minimal_response=true&_=1731567268225`;
+        const response = await ambariApi.request({
+            url: url,
+            method: "GET"
+        });
+        return response;
+    },
+    postRecommendations: async function (payload: any, STACK: string, VERSION: string) {
+      const url = `/stacks/${STACK}/versions/${VERSION}/recommendations`;
+      const response = await ambariApi.request({
+        url: url,
+        method: "POST",
+        data: payload
+      });
+      return response.data;
+    },
+    postValidations: async function (payload: any, STACK: string, VERSION: string) {
+      const url = `/stacks/${STACK}/versions/${VERSION}/validations`;
+      const response = await ambariApi.request({
+        url: url,
+        method: "POST",
+        data: payload
+      });
+      return response.data;
+    }
+}
+export default AssignMastersApi;
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/cachedServiceApi.ts b/ambari-web/latest/src/api/cachedServiceApi.ts
new file mode 100644
index 0000000000..0b9811aef4
--- /dev/null
+++ b/ambari-web/latest/src/api/cachedServiceApi.ts
@@ -0,0 +1,216 @@
+/**
+ * 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 { ServiceApi } from "./serviceApi";
+import { serviceCache } from "../Utils/cacheUtils";
+
+/**
+ * Centralized Service Component API Manager
+ * Similar to Ember.js approach - makes one consolidated API call for all components
+ * and provides cached data to individual service hooks
+ */
+class CachedServiceApiManager {
+  private static instance: CachedServiceApiManager;
+  private isPolling = false;
+  private pollingInterval: NodeJS.Timeout | null = null;
+  private subscribers = new Set<(data: any) => void>();
+
+  static getInstance(): CachedServiceApiManager {
+    if (!CachedServiceApiManager.instance) {
+      CachedServiceApiManager.instance = new CachedServiceApiManager();
+    }
+    return CachedServiceApiManager.instance;
+  }
+
+  /**
+   * Subscribe to component data updates
+   */
+  subscribe(callback: (data: any) => void): () => void {
+    this.subscribers.add(callback);
+    return () => this.subscribers.delete(callback);
+  }
+
+  /**
+   * Notify all subscribers of data updates
+   */
+  private notifySubscribers(data: any): void {
+    this.subscribers.forEach(callback => callback(data));
+  }
+
+  /**
+   * Get cached component data for a specific service
+   */
+  getServiceComponentData(serviceName: string): any {
+    return serviceCache.get(`components_${serviceName.toLowerCase()}`);
+  }
+
+  /**
+   * Get all cached component data
+   */
+  getAllComponentData(): any {
+    return serviceCache.get('all_components_data');
+  }
+
+  /**
+   * Centralized API call for all service components
+   * Similar to Ember.js approach - one call for all services
+   */
+  async fetchAllServiceComponents(clusterName: string, forceRefresh: boolean = false): Promise<any> {
+    const cacheKey = 'all_components_data';
+    
+    // Check cache first (unless force refresh)
+    if (!forceRefresh) {
+      const cachedData = serviceCache.get(cacheKey);
+      if (cachedData) {
+        return cachedData;
+      }
+    }
+
+    try {
+      
+      // OPTIMIZED: Use the same comprehensive fields as the main ServiceContext for consistency
+      const fields = `ServiceComponentInfo/service_name,host_components/HostRoles/display_name,host_components/HostRoles/host_name,host_components/HostRoles/public_host_name,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,host_components/HostRoles/stale_configs,host_components/HostRoles/ha_state,host_components/HostRoles/desired_admin_state,host_components/metrics/jvm/memHeapUsedM,host_components/metrics/jvm/HeapMemoryMax,host_components/metrics/jvm/HeapMemory [...]
+      
+      const response = await ServiceApi.getAllServiceComponentsListAndInitialMetrics(
+        clusterName,
+        fields
+      );
+
+      if (response?.data?.items) {
+        
+        // Cache the consolidated data
+        serviceCache.set(cacheKey, response.data, 30000); // 30 second TTL
+        
+        // Also cache by individual service for quick access
+        const serviceGroups = this.groupComponentsByService(response.data.items);
+        Object.entries(serviceGroups).forEach(([serviceName, data]) => {
+          serviceCache.set(`components_${serviceName.toLowerCase()}`, data, 30000);
+        });
+
+        // Notify subscribers immediately
+        this.notifySubscribers(response.data);
+        
+        return response.data;
+      }
+    } catch (error) {
+      return null;
+    }
+  }
+
+  /**
+   * Group component data by service name
+   */
+  private groupComponentsByService(items: any[]): Record<string, any[]> {
+    const groups: Record<string, any[]> = {};
+    
+    items.forEach(item => {
+      const serviceName = item.ServiceComponentInfo?.service_name;
+      if (serviceName) {
+        if (!groups[serviceName]) {
+          groups[serviceName] = [];
+        }
+        groups[serviceName].push(item);
+      }
+    });
+    
+    return groups;
+  }
+
+  /**
+   * Start centralized polling - similar to Ember.js approach
+   */
+  startPolling(clusterName: string, intervalMs: number = 5000): void {
+    if (this.isPolling) return;
+    
+    this.isPolling = true;
+    
+    // Initial fetch
+    this.fetchAllServiceComponents(clusterName);
+    
+    // Set up polling interval
+    this.pollingInterval = setInterval(() => {
+      this.fetchAllServiceComponents(clusterName);
+    }, intervalMs);
+    
+  }
+
+  /**
+   * Pause polling without clearing the interval
+   * Useful for temporarily stopping polling on specific pages
+   */
+  pausePolling(): void {
+    if (this.pollingInterval) {
+      clearInterval(this.pollingInterval);
+      this.pollingInterval = null;
+    }
+  }
+
+  /**
+   * Resume polling after it was paused
+   */
+  resumePolling(clusterName?: string, intervalMs: number = 5000): void {
+    if (this.isPolling && !this.pollingInterval && clusterName) {
+      this.pollingInterval = setInterval(() => {
+        this.fetchAllServiceComponents(clusterName);
+      }, intervalMs);
+    }
+  }
+
+  /**
+   * Stop polling completely
+   */
+  stopPolling(): void {
+    if (this.pollingInterval) {
+      clearInterval(this.pollingInterval);
+      this.pollingInterval = null;
+    }
+    this.isPolling = false;
+  }
+
+  /**
+   * Check if specific service data is available and fresh
+   */
+  hasServiceData(serviceName: string): boolean {
+    return serviceCache.has(`components_${serviceName.toLowerCase()}`);
+  }
+
+  /**
+   * Get metrics for a specific service component
+   */
+  getServiceMetrics(serviceName: string, componentName: string): any {
+    const serviceData = this.getServiceComponentData(serviceName);
+    if (!serviceData) return null;
+
+    return serviceData.find((item: any) => 
+      item.ServiceComponentInfo?.component_name === componentName
+    );
+  }
+
+  /**
+   * Clear all cached data
+   */
+  clearCache(): void {
+    serviceCache.clear();
+  }
+}
+
+// Export singleton instance
+export const cachedServiceApi = CachedServiceApiManager.getInstance();
+
+// Export the class for testing
+export { CachedServiceApiManager };
diff --git a/ambari-web/latest/src/api/centralizedServiceStateApi.ts b/ambari-web/latest/src/api/centralizedServiceStateApi.ts
new file mode 100644
index 0000000000..8de31317f5
--- /dev/null
+++ b/ambari-web/latest/src/api/centralizedServiceStateApi.ts
@@ -0,0 +1,153 @@
+/**
+ * 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 { ambariApi } from "./config/axiosConfig";
+
+interface ServiceStateData {
+  serviceName: string;
+  state: string;
+  alertsCount: number;
+  hasCriticalAlerts: boolean;
+}
+
+class CentralizedServiceStateApi {
+  private cache: Map<string, ServiceStateData> = new Map();
+  private lastFetchTime: number = 0;
+  private readonly CACHE_DURATION = 5000; // 5 seconds cache
+  private subscribers: ((data: Map<string, ServiceStateData>) => void)[] = [];
+
+  /**
+   * Fetches all service states and alerts in a single API call (Ember.js pattern)
+   * This replaces individual ServiceApi.getServiceState() calls
+   */
+  async fetchAllServiceStatesAndAlerts(clusterName: string): Promise<Map<string, ServiceStateData>> {
+    const now = Date.now();
+    
+    // Return cached data if still fresh
+    if (now - this.lastFetchTime < this.CACHE_DURATION && this.cache.size > 0) {
+      return this.cache;
+    }
+
+    try {
+      const response = await ambariApi.request({
+        url: `/clusters/${clusterName}/services?fields=ServiceInfo/state,ServiceInfo/maintenance_state&minimal_response=true`,
+        method: "GET",
+      });
+
+      // Get alerts with proper maintenance state filtering (following Ember pattern)
+      // This API call will return NO items for services/components in maintenance mode
+      const alertsResponse = await ambariApi.request({
+        url: `/clusters/${clusterName}/alerts?fields=Alert/service_name,Alert/state&Alert/state.in(CRITICAL,WARNING)&Alert/maintenance_state.in(OFF)&minimal_response=true`,
+        method: "GET",
+      });
+
+      const newCache = new Map<string, ServiceStateData>();
+
+      // Count alerts per service - API already filters out maintenance mode alerts
+      const serviceAlertsCount: { [key: string]: { critical: number; warning: number } } = {};
+      
+      alertsResponse.data.items?.forEach((alert: any) => {
+        const serviceName = alert.Alert?.service_name;
+        const alertState = alert.Alert?.state;
+        
+        if (serviceName && alertState) {
+          if (!serviceAlertsCount[serviceName]) {
+            serviceAlertsCount[serviceName] = { critical: 0, warning: 0 };
+          }
+          
+          if (alertState === 'CRITICAL') {
+            serviceAlertsCount[serviceName].critical++;
+          } else if (alertState === 'WARNING') {
+            serviceAlertsCount[serviceName].warning++;
+          }
+        }
+      });
+
+      response.data.items?.forEach((service: any) => {
+        const serviceName = service.ServiceInfo.service_name;
+        const state = service.ServiceInfo.state;
+        
+        // Use API-filtered alert counts (already excludes maintenance mode alerts)
+        const serviceAlerts = serviceAlertsCount[serviceName] || { critical: 0, warning: 0 };
+        const criticalAlerts = serviceAlerts.critical;
+        const warningAlerts = serviceAlerts.warning;
+        
+        const alertsCount = criticalAlerts + warningAlerts;
+        const hasCriticalAlerts = criticalAlerts > 0;
+
+        newCache.set(serviceName, {
+          serviceName,
+          state,
+          alertsCount,
+          hasCriticalAlerts,
+        });
+      });
+
+      this.cache = newCache;
+      this.lastFetchTime = now;
+
+      // Notify subscribers
+      this.notifySubscribers();
+
+      return this.cache;
+    } catch (error) {
+      // Return existing cache on error
+      return this.cache;
+    }
+  }
+
+  /**
+   * Get service state data for a specific service
+   */
+  getServiceStateData(serviceName: string): ServiceStateData | null {
+    return this.cache.get(serviceName) || null;
+  }
+
+  /**
+   * Subscribe to service state updates
+   */
+  subscribe(callback: (data: Map<string, ServiceStateData>) => void): () => void {
+    this.subscribers.push(callback);
+    
+    // Return unsubscribe function
+    return () => {
+      const index = this.subscribers.indexOf(callback);
+      if (index > -1) {
+        this.subscribers.splice(index, 1);
+      }
+    };
+  }
+
+  /**
+   * Notify all subscribers of data updates
+   */
+  private notifySubscribers(): void {
+    this.subscribers.forEach(callback => callback(this.cache));
+  }
+
+  /**
+   * Clear cache (useful for testing or forced refresh)
+   */
+  clearCache(): void {
+    this.cache.clear();
+    this.lastFetchTime = 0;
+  }
+}
+
+// Export singleton instance
+export const centralizedServiceStateApi = new CentralizedServiceStateApi();
diff --git a/ambari-web/latest/src/api/chooseServicesApi.ts b/ambari-web/latest/src/api/chooseServicesApi.ts
index ce7b9c9a55..c728f9cf7f 100644
--- a/ambari-web/latest/src/api/chooseServicesApi.ts
+++ b/ambari-web/latest/src/api/chooseServicesApi.ts
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { ambariApi } from "./config/axiosConfig";
 
 export const ChooseServicesApi = {
diff --git a/ambari-web/latest/src/api/clusterApi.ts b/ambari-web/latest/src/api/clusterApi.ts
index 2d7c1cb549..dca1291b8e 100644
--- a/ambari-web/latest/src/api/clusterApi.ts
+++ b/ambari-web/latest/src/api/clusterApi.ts
@@ -15,6 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+import { set } from "lodash";
 import { ambariApi, supressErrorAmbariApi } from "./config/axiosConfig";
 
 const ClusterApi = {
@@ -50,6 +52,7 @@ const ClusterApi = {
       method:"PUT",
       data
     })
+    set(response, "data.status", response?.status);
     return response.data
   },
   getCluster: async function (clusterName:string) {
@@ -62,7 +65,7 @@ const ClusterApi = {
   },
   getAllClusters: async function () {
     const url = `/clusters`;
-    const response = await ambariApi.request({
+    const response = await supressErrorAmbariApi.request({
       url: url,
       method: "GET",
     });
@@ -86,7 +89,7 @@ const ClusterApi = {
   },
   getRequestById: async function (clusterName: string,requestId:number|string) {
     const url = `/clusters/${clusterName}/requests/${requestId}?fields=*,tasks/Tasks/request_id,tasks/Tasks/command,tasks/Tasks/command_detail,tasks/Tasks/ops_display_name,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true`;
-    const response = await ambariApi.request({
+    const response = await supressErrorAmbariApi.request({
       url: url,
       method: "GET",
     });
@@ -116,7 +119,6 @@ const ClusterApi = {
         method: "GET"
     });
     const clusterName = response?.data?.items[0]?.Clusters?.cluster_name;
-    console.log("CLUSTER NAME", response.data.items[0].Clusters.cluster_name)
     return clusterName;
   },
   getClusterData: async function () {
@@ -127,8 +129,8 @@ const ClusterApi = {
     });
     return response.data;
   },
-  getPersistData: async function (key:any) {
-    const url = `/persist/${key}`;
+  getPersistData: async function (key?: any) {
+    const url = key ? `/persist/${key}` : '/persist';
     const response = await supressErrorAmbariApi.request({
       url: url,
       method: "GET",
@@ -197,7 +199,17 @@ const ClusterApi = {
       data: payload,
     });
     return response.data;
+  },
+
+  getClusterMetrics: async function (clusterName: string, fields: string) {
+    const url = `/clusters/${clusterName}?fields=${fields}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+
   }
-  }
+}
 
 export default ClusterApi;
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/clusterDeployment.ts b/ambari-web/latest/src/api/clusterDeployment.ts
new file mode 100644
index 0000000000..1e6d1cba10
--- /dev/null
+++ b/ambari-web/latest/src/api/clusterDeployment.ts
@@ -0,0 +1,67 @@
+/**
+ * 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 { ambariApi } from "./config/axiosConfig";
+const ClusterDeploymentApi = {
+    createCluster:async function createCluster(clusterName:string,data:any){{
+        const url=`/clusters/${clusterName}`;
+        const response=await ambariApi.request({
+            url,
+            method:"POST",
+            data
+        })
+        return response.data
+    }},
+    createSelectedServices:async function createCluster(clusterName:string,data:any){{
+        const url=`/clusters/${clusterName}/services`;
+        return  ambariApi.request({
+            url,
+            method:"POST",
+            data
+        })
+    }},
+    addRequestToCreateComponent:async function addRequestToCreateComponent(clusterName:string,serviceName:string,data:any){{
+        const url=`/clusters/${clusterName}/services?ServiceInfo/service_name=${serviceName}`
+        const response=await ambariApi.request({
+            url,
+            method:"POST",
+            data
+        })
+        return response.data
+    }},
+    registerHostToCluster:async function registerHostToCluster(clusterName:string,data:any){{
+        const url=`/clusters/${clusterName}/hosts`
+        const response=await ambariApi.request({
+            url,
+            method:"POST",
+            data
+        })
+        return response.data
+    }},
+    applyClusterConfigs: async function(clusterName:string, applyConfigsPaylpoad: any) {
+        const url = `/clusters/${clusterName}`;
+        return ambariApi.request({
+          url: url,
+          method: "PUT",
+          data: applyConfigsPaylpoad
+        });
+
+      }
+};
+
+export default ClusterDeploymentApi;
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/validations.ts b/ambari-web/latest/src/api/componentApi.ts
similarity index 80%
copy from ambari-web/latest/src/api/validations.ts
copy to ambari-web/latest/src/api/componentApi.ts
index 27ea68e03b..de622077ff 100644
--- a/ambari-web/latest/src/api/validations.ts
+++ b/ambari-web/latest/src/api/componentApi.ts
@@ -15,18 +15,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { ambariApi } from "./config/axiosConfig";
 
-const ValidationsApi = {
-  validateMapping: async (stack:string,version:string,data:any) => {
-    const url = `/stacks/${stack}/versions/${version}/validations`;
+const ComponentApi = {
+
+  editComponent: async function (clusterName:string,data:any) {
+    const url = `/clusters/${clusterName}/components`;
     const response = await ambariApi.request({
-      url,
-      data,
-      method: "POST",
+      url: url,
+      method: "PUT",
+      data
     });
     return response.data;
   },
 };
 
-export default ValidationsApi;
\ No newline at end of file
+export default ComponentApi;
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/config/axiosConfig.ts b/ambari-web/latest/src/api/config/axiosConfig.ts
index af5cbffc43..8f98a7cab2 100644
--- a/ambari-web/latest/src/api/config/axiosConfig.ts
+++ b/ambari-web/latest/src/api/config/axiosConfig.ts
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import axios from "axios";
 import { toast } from "react-hot-toast";
 import { get } from "lodash";
diff --git a/ambari-web/latest/src/api/LogApi.ts b/ambari-web/latest/src/api/configHistoryApi.ts
similarity index 57%
copy from ambari-web/latest/src/api/LogApi.ts
copy to ambari-web/latest/src/api/configHistoryApi.ts
index 0011202dc7..1546d0ae10 100644
--- a/ambari-web/latest/src/api/LogApi.ts
+++ b/ambari-web/latest/src/api/configHistoryApi.ts
@@ -15,18 +15,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ambariApi } from "./config/axiosConfig";
 
-const LogApi = {
+import { ambariApi } from "./config/axiosConfig";
 
-  getLogData: async function (clusterName:string, requestId:string) {
-    const url = `/clusters/${clusterName}/requests/${requestId}?fields=tasks/Tasks/command,tasks/Tasks/command_detail,tasks/Tasks/ops_display_name,tasks/Tasks/exit_code,tasks/Tasks/start_time,tasks/Tasks/end_time,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true`;
+const ConfigHistoryApi = {
+  fetchPageSize: async (clusterName: string) => {
+    const url = `/clusters/${clusterName}/configurations/service_config_versions?page_size=1&minimal_response=true`;
+    const response = await ambariApi.request({
+      url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  fetchConfigHistory: async (clusterName: string, parameters: string) => {
+    const url = `/clusters/${clusterName}/configurations/service_config_versions?${parameters}fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note,is_cluster_compatible,stack_id&minimal_response=true`;
     const response = await ambariApi.request({
-      url: url,
+      url,
       method: "GET",
     });
     return response.data;
   },
 };
 
-export default LogApi;
\ No newline at end of file
+export default ConfigHistoryApi;
diff --git a/ambari-web/latest/src/api/credentialsApi.ts b/ambari-web/latest/src/api/credentialsApi.ts
new file mode 100644
index 0000000000..6db96bb46b
--- /dev/null
+++ b/ambari-web/latest/src/api/credentialsApi.ts
@@ -0,0 +1,97 @@
+/**
+ * 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 { ambariApi } from "./config/axiosConfig";
+
+const CredentialsApi = {
+  createCredentials: async function (
+    clusterName: string,
+    alias: string,
+    data: { resource: string }
+  ) {
+    const url = `/clusters/${clusterName}/credentials/${alias}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "POST",
+      data: {
+        Credential: data.resource,
+      },
+    });
+    return response.data;
+  },
+  getCredentials: async function (
+    clusterName: string,
+    alias: string,
+  ) {
+    const url = `/clusters/${clusterName}/credentials/${alias}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  deleteCredentials: async function (
+    clusterName: string,
+    alias: string,
+  ) {
+    const url = `/clusters/${clusterName}/credentials/${alias}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "DELETE",
+    });
+    return response.data;
+  },
+  updateCredentials: async function (
+    clusterName: string,
+    alias: string,
+    data:{resource:string}
+  ) {
+    const url = `/clusters/${clusterName}/credentials/${alias}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "PUT",
+      data:{
+        Credential:data.resource
+      }
+    });
+    return response.data;
+  },
+  listCredentials: async function (
+    clusterName: string,
+  ) {
+    const url = `/clusters/${clusterName}/credentials?fields=Credential/*`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  credentialsStoreInfo: async function (
+    clusterName: string,
+  ) {
+    const url = `/clusters/${clusterName}?fields=Clusters/credential_store_properties`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  
+};
+
+export default CredentialsApi
diff --git a/ambari-web/latest/src/api/hostsApi.ts b/ambari-web/latest/src/api/hostsApi.ts
index 789c6b4c53..7f73173107 100644
--- a/ambari-web/latest/src/api/hostsApi.ts
+++ b/ambari-web/latest/src/api/hostsApi.ts
@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 
+import { set } from "lodash";
 import { ambariApi } from "./config/axiosConfig";
 
 export const HostsApi = {
@@ -181,6 +182,7 @@ export const HostsApi = {
         },
       },
     });
+    set(response, "data.status", response.status);
     return response.data;
   },
   updateHostComponents: async function (
@@ -209,6 +211,7 @@ export const HostsApi = {
         },
       }),
     });
+    set(response, "data.status", response?.status)
     return response.data;
   },
   deleteHostComponent: async function (
@@ -221,6 +224,7 @@ export const HostsApi = {
       url: url,
       method: "DELETE",
     });
+    set(response, "data.status", response.status);
     return response.data;
   },
   deleteHostComponents: async function (data: any, clusterName: string) {
@@ -239,6 +243,7 @@ export const HostsApi = {
       method: "POST",
       data: data,
     });
+     set(response, "data.status", response?.status)
     return response.data;
   },
   getHostsData: async function (fields: string) {
@@ -477,6 +482,16 @@ export const HostsApi = {
     });
     return response.data;
   },
+  commonServiceConfigurationsMove: async function (clusterName: string, data: any) {
+    const url = `/clusters/${clusterName}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "PUT",
+      data,
+    });
+    set(response, "data.status", response?.status)
+    return response.data;
+  },
   updateServicePassiveState: async function (
     clusterName: string,
     serviceName: string,
@@ -658,4 +673,31 @@ export const HostsApi = {
     });
     return response.data;
   },
+  transitionToObserver: async function (clusterName: string, data: any) {
+    const url = `/clusters/${clusterName}/requests`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "POST",
+      data: JSON.stringify({
+        RequestInfo: {
+          context: data.context,
+          command: "MAKEOBSERVER",
+          operation_level: {
+            level: "HOST_COMPONENT",
+            cluster_name: clusterName,
+            host_name: data.hostName,
+            service_name: "HDFS",
+          },
+        },
+        "Requests/resource_filters": [
+          {
+            service_name: "HDFS",
+            component_name: "NAMENODE",
+            hosts: data.hostName,
+          },
+        ],
+      }),
+    });
+    return response.data;
+  },
 };
diff --git a/ambari-web/latest/src/api/kerberosApi.ts b/ambari-web/latest/src/api/kerberosApi.ts
index 9107ed9cd9..9d736c95e7 100644
--- a/ambari-web/latest/src/api/kerberosApi.ts
+++ b/ambari-web/latest/src/api/kerberosApi.ts
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-import { ambariApi } from "./config/axiosConfig";
+import { ambariApi, supressErrorAmbariApi } from "./config/axiosConfig";
 
 const KerberosApi = {
   getKerberosDescriptorProperties: async function (
@@ -57,38 +57,65 @@ const KerberosApi = {
     });
     return response.data;
   },
-  saveKerberosData: async function (clusterName: string, payload: any) {
-    const url = `clusters/${clusterName}/artifacts/kerberos_descriptor`;
-    const response = await ambariApi.request({
+  saveKerberosData: async function(clusterName: string, payload: any) {
+    const url = `clusters/${clusterName}/artifacts/kerberos_descriptor`
+    const response = await supressErrorAmbariApi.request({
       url: url,
       method: "POST",
-      data: payload,
-    });
+      data: payload
+    })
+    return response.data;
+  },
+  saveAndEditKerberosData: async function(clusterName: string, payload: any) {
+    const url = `clusters/${clusterName}/artifacts/kerberos_descriptor`
+    const response = await supressErrorAmbariApi.request({
+      url: url,
+      method: "PUT",
+      data: payload
+    })
     return response.data;
   },
   postKDCAdminCredentials: async function (clusterName: string, payload: any) {
-    const url = `clusters/${clusterName}/credentials/kdc.admin.credential`;
-    const response = await ambariApi.request({
+    const url = `clusters/${clusterName}/credentials/kdc.admin.credential`
+    const response = await supressErrorAmbariApi.request({
       url: url,
       method: "POST",
-      data: payload,
-    });
+      data: payload
+    })
+    return response.data;
+  },
+  postKDCAdminCredentialsSupress: async function (clusterName: string, payload: any) {
+    const url = `clusters/${clusterName}/credentials/kdc.admin.credential`
+    const response = await supressErrorAmbariApi.request({
+      url: url,
+      method: "POST",
+      data: payload
+    })
+    return response.data;
+  },
+  submitKDCAdminCredentials: async function (clusterName: string, payload: any, method: string) {
+    const url = `clusters/${clusterName}/credentials/kdc.admin.credential`
+    const response = await supressErrorAmbariApi.request({
+      url: url,
+      method: method,
+      data: payload
+    })
     return response.data;
   },
   deleteKDCAdminCredentials: async function (clusterName: string) {
-    const url = `clusters/${clusterName}/credentials/kdc.admin.credential`;
+    const url = `clusters/${clusterName}/credentials/kdc.admin.credential`
     const response = await ambariApi.request({
       url: url,
       method: "DELETE",
-    });
+    })
     return response.data;
   },
   getKDCAdminCredentials: async function (clusterName: string) {
-    const url = `clusters/${clusterName}/credentials?fields=Credential/*`;
-    const response = await ambariApi.request({
+    const url = `clusters/${clusterName}/credentials?fields=Credential/*`
+    const response = await supressErrorAmbariApi.request({
       url: url,
       method: "GET",
-    });
+    })
     return response.data;
   },
 
@@ -110,7 +137,7 @@ const KerberosApi = {
     serviceName: string
   ) {
     const url = `clusters/${clusterName}/services/${serviceName}`;
-    const response = await ambariApi.request({
+    const response = await supressErrorAmbariApi.request({
       url: url,
       method: "DELETE",
     });
@@ -126,6 +153,15 @@ const KerberosApi = {
     });
     return response.data;
   },
+
+  getCredentialStoreInfo: async function (clusterName: string) {
+    const url = `clusters/${clusterName}?fields=Clusters/credential_store_properties`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
 };
 
 export default KerberosApi;
diff --git a/ambari-web/latest/src/api/LogApi.ts b/ambari-web/latest/src/api/logApi.ts
similarity index 98%
copy from ambari-web/latest/src/api/LogApi.ts
copy to ambari-web/latest/src/api/logApi.ts
index 0011202dc7..8ecec1b9ad 100644
--- a/ambari-web/latest/src/api/LogApi.ts
+++ b/ambari-web/latest/src/api/logApi.ts
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { ambariApi } from "./config/axiosConfig";
 
 const LogApi = {
diff --git a/ambari-web/latest/src/api/loginApi.ts b/ambari-web/latest/src/api/loginApi.ts
index 97cbc5e66c..593c0cda82 100644
--- a/ambari-web/latest/src/api/loginApi.ts
+++ b/ambari-web/latest/src/api/loginApi.ts
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import {ambariApi} from "./config/axiosConfig.ts";
 import {misc} from "../Utils/misc.ts";
 import { db } from "../Utils/db";
diff --git a/ambari-web/latest/src/api/metricsApi.ts b/ambari-web/latest/src/api/metricsApi.ts
index 0c6413ca1b..203f4f9752 100644
--- a/ambari-web/latest/src/api/metricsApi.ts
+++ b/ambari-web/latest/src/api/metricsApi.ts
@@ -15,58 +15,97 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ambariApi } from "./config/axiosConfig";
 
-const metricsApi = {
+import { ambariApi, supressErrorAmbariApi } from "./config/axiosConfig";
+
+const MetricsApi = {
   getWidgets: async function (userName: string, urlParams: string ) {
+    const url = `/users/${userName}/activeWidgetLayouts?${urlParams}`;
+
     try {
-      const url = `/users/${userName}/activeWidgetLayouts?${urlParams}`;
       const response = await ambariApi.request({
         url: url,
         method: "GET",
       });
       return response.data;
     } catch (error) {
-      console.warn("Error fetching active widgets from API, using fallback data:", error);
-      // Extract service name from urlParams (format: WidgetLayoutInfo/section_name=SERVICE_SUMMARY)
-      const serviceMatch = urlParams.match(/section_name=(\w+)_SUMMARY/);
-      const serviceName = serviceMatch ? serviceMatch[1] : "HDFS";
-      
-      // Return a fallback structure that matches the expected format
-      return {
-        items: [
-          {
-            WidgetLayoutInfo: {
-              id: "fallback-layout",
-              layout_name: `${serviceName.toLowerCase()}_dashboard`,
-              section_name: `${serviceName}_SUMMARY`,
-              scope: "USER",
-              widgets: [
-                {
-                  WidgetInfo: {
-                    id: "fallback-active-graph",
-                    widget_name: `${serviceName} Metrics Graph`,
-                    widget_type: "GRAPH",
-                    metrics: JSON.stringify([
-                      {
-                        name: "active_metric_graph",
-                        service_name: serviceName,
-                        component_name: serviceName === "HDFS" ? "NAMENODE" : "RESOURCEMANAGER",
-                        metric_path: "metrics/jvm/HeapMemoryMax",
-                      }
-                    ]),
-                    values: JSON.stringify([]),
-                    properties: JSON.stringify({}),
-                    scope: "USER",
-                    author: userName,
-                    description: "Active graph widget (fallback)"
-                  }
-                }
-              ]
-            }
-          }
-        ]
-      };
+      console.warn("Error fetching active widgets from API:", error);
+      throw error; // Let the caller handle the fallback logic
+    }
+  },
+
+  getDefaultWidgetLayoutByName: async function (layoutName: string) {
+    try {
+      const urlParams = `WidgetLayoutInfo/layout_name=${layoutName}`;
+      const url = `/widget_layouts?${urlParams}`;
+      const response = await supressErrorAmbariApi.request({
+        url: url,
+        method: "GET",
+      });
+      return response.data;
+    } catch (error) {
+      console.warn("Error fetching default widget layout:", error);
+      throw error;
+    }
+  },
+
+  createUserWidgetLayout: async function (clusterName: string, widgetLayoutData: any) {
+    try {
+      const url = `/clusters/${clusterName}/widget_layouts`;
+      const response = await ambariApi.request({
+        url: url,
+        method: "POST",
+        data: widgetLayoutData,
+      });
+      return response.data;
+    } catch (error) {
+      console.warn("Error creating user widget layout:", error);
+      throw error;
+    }
+  },
+
+  getAllActiveWidgetLayouts: async function (userName: string) {
+    try {
+      const url = `/users/${userName}/activeWidgetLayouts`;
+      const response = await ambariApi.request({
+        url: url,
+        method: "GET",
+      });
+      return response.data;
+    } catch (error) {
+      console.warn("Error fetching all active widget layouts:", error);
+      throw error;
+    }
+  },
+
+  saveActiveWidgetLayouts: async function (userName: string, activeWidgetLayouts: any) {
+    try {
+      const url = `/users/${userName}/activeWidgetLayouts`;
+      const response = await ambariApi.request({
+        url: url,
+        method: "PUT",
+        data: activeWidgetLayouts,
+      });
+      return response.data;
+    } catch (error) {
+      console.warn("Error saving active widget layouts:", error);
+      throw error;
+    }
+  },
+
+  getWidgetsByService: async function (clusterName: string, serviceName: string) {
+    try {
+      // Get widgets for the specific service
+      const urlParams = `WidgetInfo/widget_type.in(GRAPH,NUMBER,GAUGE)&WidgetInfo/scope=CLUSTER&WidgetInfo/metrics.matches(.*"service_name":"${serviceName}".*)&fields=*`;
+      const url = `/clusters/${clusterName}/widgets?${urlParams}`;
+      const response = await ambariApi.request({
+        url: url,
+        method: "GET",
+      });
+      return response.data;
+    } catch (error) {
+      console.warn("Error fetching widgets by service:", error);
+      throw error;
     }
   },
   getAllSharedWidgets: async function (clusterName: string) {
@@ -281,30 +320,21 @@ const metricsApi = {
     hostComponentCriteria: string,
     metricsPath: string
   ) {
+    // Don't encode the metrics path - let axios handle it properly
+    // encodeURIComponent breaks comma-separated field lists
+    const url = `/clusters/${clusterName}/host_components?HostRoles/component_name=${componentName}&${hostComponentCriteria}&fields=${metricsPath}&format=null_padding`;
+
     try {
-      const url = `/clusters/${clusterName}/host_components?HostRoles/component_name=${componentName}&${hostComponentCriteria}&fields=${metricsPath}&format=null_padding`;
       const response = await ambariApi.request({
         url: url,
         method: "GET",
       });
       return response.data;
     } catch (error) {
-      console.warn("Error fetching host component metrics, returning fallback data:", error);
-      // Return a fallback structure with empty metrics data
+      console.error("Error fetching host component metrics:", error);
+      // Return empty structure to avoid displaying incorrect data
       return {
-        items: [
-          {
-            href: "#",
-            HostRoles: {
-              component_name: componentName,
-              host_name: "localhost"
-            },
-            metrics: {
-              dfs: { namenode: { ClusterId: "fallback-cluster-id" } },
-              jvm: { HeapMemoryMax: 1073741824, HeapMemoryUsed: 536870912 }
-            }
-          }
-        ]
+        items: []
       };
     }
   },
@@ -314,25 +344,25 @@ const metricsApi = {
     serviceName: string,
     metricsPath: string
   ) {
+    // Don't encode the metrics path - let axios handle it properly
+    // encodeURIComponent breaks comma-separated field lists
+    const url = `/clusters/${clusterName}/services/${serviceName}/components/${componentName}?fields=${metricsPath}&format=null_padding`;
+
     try {
-      const url = `/clusters/${clusterName}/services/${serviceName}/components/${componentName}?fields=${metricsPath}&format=null_padding`;
       const response = await ambariApi.request({
         url: url,
         method: "GET",
       });
       return response.data;
     } catch (error) {
-      console.warn("Error fetching service component metrics, returning fallback data:", error);
-      // Return a fallback structure with empty metrics data
+      console.error("Error fetching service component metrics:", error);
+      // Return empty structure to avoid displaying incorrect data
       return {
         ServiceComponentInfo: {
           component_name: componentName,
           service_name: serviceName
         },
-        metrics: {
-          dfs: { namenode: { ClusterId: "fallback-cluster-id" } },
-          jvm: { HeapMemoryMax: 1073741824, HeapMemoryUsed: 536870912 }
-        }
+        metrics: {}
       };
     }
   },
@@ -407,4 +437,4 @@ const metricsApi = {
   },
 };
 
-export default metricsApi;
+export default MetricsApi;
diff --git a/ambari-web/latest/src/api/nameNodeFederationApi.ts b/ambari-web/latest/src/api/nameNodeFederationApi.ts
new file mode 100644
index 0000000000..fac2ea648e
--- /dev/null
+++ b/ambari-web/latest/src/api/nameNodeFederationApi.ts
@@ -0,0 +1,56 @@
+/**
+ * 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 { set } from "lodash";
+import { ambariApi } from "./config/axiosConfig";
+
+const NameNodeFederationApi = {
+    formatNameNode : async function(clusterName: string, payload: any) {
+        const url = `/clusters/${clusterName}/requests`
+        const response = await ambariApi.request({
+            url: url,
+            method: "POST",
+            data: payload
+        });
+        set(response, "data.status", response?.status)
+        return response.data;
+    },
+
+    formatZKFC : async function(clusterName: string, payload: any) {
+        const url = `/clusters/${clusterName}/requests`
+        const response = await ambariApi.request({
+            url: url,
+            method: "POST",
+            data: payload
+        });
+         set(response, "data.status", response?.status)
+        return response.data;
+    },
+    bootStrapNameNode : async function(clusterName: string, payload: any) {
+        const url = `/clusters/${clusterName}/requests`
+        const response = await ambariApi.request({
+            url: url,
+            method: "POST",
+            data: payload
+        });
+         set(response, "data.status", response?.status)
+        return response.data;
+    }
+}
+
+export default NameNodeFederationApi;
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/validations.ts b/ambari-web/latest/src/api/persistanceApi.ts
similarity index 83%
copy from ambari-web/latest/src/api/validations.ts
copy to ambari-web/latest/src/api/persistanceApi.ts
index 27ea68e03b..a5dec99aaa 100644
--- a/ambari-web/latest/src/api/validations.ts
+++ b/ambari-web/latest/src/api/persistanceApi.ts
@@ -15,11 +15,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { ambariApi } from "./config/axiosConfig";
 
-const ValidationsApi = {
-  validateMapping: async (stack:string,version:string,data:any) => {
-    const url = `/stacks/${stack}/versions/${version}/validations`;
+const PersistanceApi = {
+  validateMapping: async (data:any) => {
+    const url = `/persist`;
     const response = await ambariApi.request({
       url,
       data,
@@ -29,4 +30,4 @@ const ValidationsApi = {
   },
 };
 
-export default ValidationsApi;
\ No newline at end of file
+export default PersistanceApi;
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/recommendationsApi.ts b/ambari-web/latest/src/api/quicklinksApi.ts
similarity index 67%
copy from ambari-web/latest/src/api/recommendationsApi.ts
copy to ambari-web/latest/src/api/quicklinksApi.ts
index e2f0f7a707..c97d482776 100644
--- a/ambari-web/latest/src/api/recommendationsApi.ts
+++ b/ambari-web/latest/src/api/quicklinksApi.ts
@@ -15,18 +15,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ambariApi } from "./config/axiosConfig";
 
-const RecommendationsApi = {
-  loadRecommendations: async (stack:string,version:string,data:any) => {
-    const url = `/stacks/${stack}/versions/${version}/recommendations`;
-    const response = await ambariApi.request({
-      url,
-      data,
-      method: "POST",
-    });
-    return response.data;
-  },
-};
+import { ambariApi } from "./config/axiosConfig";
 
-export default RecommendationsApi;
\ No newline at end of file
+export const QuicklinksApi = {
+    getQuicklinks: async (stackVersion: string,stackName:string, serviceName: string) => {
+        const url = `/stacks/${stackName}/versions/${stackVersion}/services/${serviceName}/quicklinks?QuickLinkInfo/default=true&fields=*&_=${Date.now()}'`;
+        const response = await ambariApi.request({
+            url: url,
+            method: "GET",
+        });
+        return response;
+    }
+}
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/recommendationsApi.ts b/ambari-web/latest/src/api/recommendationsApi.ts
index e2f0f7a707..4a9aaf71a3 100644
--- a/ambari-web/latest/src/api/recommendationsApi.ts
+++ b/ambari-web/latest/src/api/recommendationsApi.ts
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { ambariApi } from "./config/axiosConfig";
 
 const RecommendationsApi = {
diff --git a/ambari-web/latest/src/api/requestApi.ts b/ambari-web/latest/src/api/requestApi.ts
index 536d4cc948..f0a2847aa5 100644
--- a/ambari-web/latest/src/api/requestApi.ts
+++ b/ambari-web/latest/src/api/requestApi.ts
@@ -15,12 +15,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { set } from "lodash";
-import { ambariApi } from "./config/axiosConfig";
+import { ambariApi, supressErrorAmbariApi } from "./config/axiosConfig";
 export const RequestApi = {
     getRequestStatus: async function (clusterName: string,requestId:string) {
         const url = `/clusters/${clusterName}/requests/${requestId}?fields=*,tasks/Tasks/request_id,tasks/Tasks/command,tasks/Tasks/command_detail,tasks/Tasks/ops_display_name,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true`;
-        const response = await ambariApi.request({
+        const response = await supressErrorAmbariApi.request({
             url: url,
             method: "GET",
         });
@@ -44,6 +45,7 @@ export const RequestApi = {
             "Content-Type":"text/plain"
           }
         });
+        set(response, "data.status", response.status);
         return response.data;
     },
     startServices: async function (clusterName: string, payload: any, params: string, method="PUT"){
@@ -68,6 +70,7 @@ export const RequestApi = {
           "Content-Type":"text/plain"
         }
       })
+      set(response, "data.status", response.status);
       return response.data;
     },
     postRequest: async function (clusterName: string, payload: any, method="POST") {
@@ -77,6 +80,7 @@ export const RequestApi = {
         method: method,
         data: payload,
       })
+      set(response, "data.status", response.status);
       return response.data;
     },
     getServices: async function (clusterName: string, payload: any, params: string, method="PUT"){
@@ -119,6 +123,7 @@ export const RequestApi = {
           "Content-Type":"text/plain"
         }
       })
+      set(response, "data.status", response.status);
       return response.data;
     },
     regenerateKeytabs: async function (clusterName: string, payload: any, params: string) {
@@ -131,6 +136,7 @@ export const RequestApi = {
           "Content-Type": "text/plain"
         }
       })
+      set(response, "data.status", response.status);
       return response.data;
     },
     kerberosDescriptor: async function (clusterName: string, payload: any) {
diff --git a/ambari-web/latest/src/api/ServiceApi.ts b/ambari-web/latest/src/api/serviceApi.ts
similarity index 99%
rename from ambari-web/latest/src/api/ServiceApi.ts
rename to ambari-web/latest/src/api/serviceApi.ts
index 7aeb4ddf82..e297196183 100644
--- a/ambari-web/latest/src/api/ServiceApi.ts
+++ b/ambari-web/latest/src/api/serviceApi.ts
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { set } from "lodash";
 import { ambariApi } from "./config/axiosConfig";
 
diff --git a/ambari-web/latest/src/api/serviceConfigApi.ts b/ambari-web/latest/src/api/serviceConfigApi.ts
new file mode 100644
index 0000000000..a66adcd0fd
--- /dev/null
+++ b/ambari-web/latest/src/api/serviceConfigApi.ts
@@ -0,0 +1,38 @@
+/**
+ * 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 { ambariApi } from "./config/axiosConfig";
+export const ServiceConfigApi = {
+    getServiceConfig: async function (clusterName: string, serviceName: string) {
+        const url = `/clusters/${clusterName}/configurations/service_config_versions?service_name=${serviceName}&fields=service_config_version,user,hosts,group_id,group_name,is_current,createtime,service_name,service_config_version_note,stack_id,is_cluster_compatible&sortBy=service_config_version.desc&minimal_response=true`;
+        const response = await ambariApi.request({
+            url: url,
+            method: "GET",
+        });
+        return response;
+    },
+    setIsCurrent: async function (clusterName: string, selectedServices: string[]) {
+        const servicesQuery = selectedServices.join(',');
+        const url = `/clusters/${clusterName}/configurations/service_config_versions?service_name.in(${servicesQuery})&is_current=true&fields=*&_=${Date.now()}\`;`
+        const response = await ambariApi.request({
+            url: url,
+            method: "GET",
+        });
+        return response;
+    },
+};
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/validations.ts b/ambari-web/latest/src/api/validations.ts
index 27ea68e03b..5c41e59a6c 100644
--- a/ambari-web/latest/src/api/validations.ts
+++ b/ambari-web/latest/src/api/validations.ts
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { ambariApi } from "./config/axiosConfig";
 
 const ValidationsApi = {
diff --git a/ambari-web/latest/src/api/VersionsApi.ts b/ambari-web/latest/src/api/versionsApi.ts
similarity index 68%
rename from ambari-web/latest/src/api/VersionsApi.ts
rename to ambari-web/latest/src/api/versionsApi.ts
index 5f0def0033..f36ac21fc0 100644
--- a/ambari-web/latest/src/api/VersionsApi.ts
+++ b/ambari-web/latest/src/api/versionsApi.ts
@@ -1,3 +1,4 @@
+
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +19,171 @@
 
 import { ambariApi } from "./config/axiosConfig";
 const VersionsApi = {
+  versionsList: async function (repoVersion: string, clusterName: string) {
+    const url = `/clusters/${clusterName}/stack_versions?fields=*&ClusterStackVersions/repository_version=${repoVersion}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getRepos: async function () {
+    const url = `/stacks?fields=versions/repository_versions/RepositoryVersions`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getClusterInfo: async function () {
+    const url = `/clusters?fields=Clusters/cluster_id`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getVersionDefinitions: async function () {
+    const url = `/version_definitions?fields=VersionDefinition/stack_default,VersionDefinition/stack_repo_update_link_exists,VersionDefinition/max_jdk,VersionDefinition/min_jdk,operating_systems/repositories/Repositories/*,operating_systems/OperatingSystems/*,VersionDefinition/stack_services,VersionDefinition/repository_version&VersionDefinition/show_available=true&VersionDefinition/stack_name=VDP&_=1727429673209`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getAllVersionDefinitions: async function () {
+    const url = `/version_definitions`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  getVersionOperatingSystems: async function (versionName: string) {
+    const url = `/stacks/VDP/versions/${versionName}?fields=operating_systems/repositories/Repositories`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  readVersionInfo: async function (
+    payload: any,
+    headers = {},
+    isDryRun = true
+  ) {
+    const url = `/version_definitions?skip_url_check=true${
+      isDryRun ? "&dry_run=true" : ""
+    }`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "POST",
+      headers: { ...headers },
+      data: payload,
+    });
+    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;
+  },
+  getRepoDetails: async (stack: string, version: string) => {
+    const url = `/stacks/${stack}/versions?fields=repository_versions/operating_systems/repositories/*,repository_versions/operating_systems/OperatingSystems/*,repository_versions/RepositoryVersions/*&repository_versions/RepositoryVersions/repository_version=${version}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  deleteRepositoryVersion: async function deleteRepositoryVersion(
+    stack: string,
+    stackVersion: string,
+    repositoryVersion: string
+  ) {
+    const url = `/stacks/${stack}/versions/${stackVersion}/repository_versions/${repositoryVersion}`;
+    const response = await ambariApi.request({
+      url: url,
+      method: "DELETE",
+    });
+    return response.data;
+  },
+  postVersionDefinitionFile: async function postVersionDefinitionFile(
+    data: any
+  ) {
+    const url = `/version_definitions`;
+    const response = await ambariApi.request({
+      url,
+      method: "POST",
+      data,
+    });
+    return response.data;
+  },
+  getVersionDefinition: async function getVersionDefinition() {
+    const url = `/version_definitions`;
+    const response = await ambariApi.request({
+      url,
+      method: "GET",
+    });
+    return response.data;
+  },
+  updateRepoOSInfo: async function updateRepoOSInfo(
+    stackName: string,
+    stackVersion: string,
+    repoVersionId: string,
+    data: any
+  ) {
+    {
+      const url = `/stacks/${stackName}/versions/${stackVersion}/repository_versions/${repoVersionId}`;
+      const response = await ambariApi.request({
+        url,
+        method: "PUT",
+        data,
+      });
+      return response.data;
+    }
+  },
+  updateOSInfo: async function updateRepoOSInfo(
+    stackName: string,
+    stackVersion: string,
+    operatingSystem: string,
+    repoVersionId: string,
+    data: any
+  ) {
+    {
+      const url = `/stacks/${stackName}/versions/${stackVersion}/operating_systems/${operatingSystem}/repositories/${repoVersionId}`;
+      const response = await ambariApi.request({
+        url,
+        method: "PUT",
+        data,
+      });
+      return response.data;
+    }
+  },
   getServices: async function (clusterName: string) {
     const url = `/clusters/${clusterName}/stack_versions?fields=*,repository_versions/*`;
     const response = await ambariApi.request({
@@ -33,7 +199,7 @@ const VersionsApi = {
       method: "GET",
     });
     return response.data;
-  },
+  }, 
   get_supported_upgradeTypes: async function (
     stackName: string,
     stackVersion: string,
@@ -75,32 +241,6 @@ const VersionsApi = {
     });
     return response.data;
   },
-  getUpgradeItem: async function (
-    upgradeId: number,
-    groupId: number,
-    stageId: number,
-    clusterName: string
-  ) {
-    const url =
-      `/clusters/${clusterName}/upgrades/${upgradeId}/upgrade_groups/${groupId}/upgrade_items/${stageId}?fields=` +
-      [
-        "UpgradeItem/group_id",
-        "UpgradeItem/stage_id",
-        "tasks/Tasks/command_detail",
-        "tasks/Tasks/host_name",
-        "tasks/Tasks/role",
-        "tasks/Tasks/request_id",
-        "tasks/Tasks/stage_id",
-        "tasks/Tasks/status",
-        "tasks/Tasks/structured_out",
-      ].join(",") +
-      "&minimal_response=true";
-    const response = await ambariApi.request({
-      url: url,
-      method: "GET",
-    });
-    return response.data;
-  },
   getTasksList: async function (
     upgradeId: number,
     groupId: number,
@@ -141,6 +281,32 @@ const VersionsApi = {
     });
     return response.data;
   },
+  getUpgradeItem: async function (
+    upgradeId: number,
+    groupId: number,
+    stageId: number,
+    clusterName: string
+  ) {
+    const url =
+      `/clusters/${clusterName}/upgrades/${upgradeId}/upgrade_groups/${groupId}/upgrade_items/${stageId}?fields=` +
+      [
+        "UpgradeItem/group_id",
+        "UpgradeItem/stage_id",
+        "tasks/Tasks/command_detail",
+        "tasks/Tasks/host_name",
+        "tasks/Tasks/role",
+        "tasks/Tasks/request_id",
+        "tasks/Tasks/stage_id",
+        "tasks/Tasks/status",
+        "tasks/Tasks/structured_out",
+      ].join(",") +
+      "&minimal_response=true";
+    const response = await ambariApi.request({
+      url: url,
+      method: "GET",
+    });
+    return response.data;
+  },
   abortUpgrade: async function (clusterName: string, upgradeId: number) {
     const url = `/clusters/${clusterName}/upgrades/${upgradeId}`;
     const response = await ambariApi.request({
@@ -182,14 +348,6 @@ const VersionsApi = {
     });
     return response.data; 
   },
-  getRepoDetails: async (stack: string, version: string) => {
-    const url = `/stacks/${stack}/versions?fields=repository_versions/operating_systems/repositories/*,repository_versions/operating_systems/OperatingSystems/*,repository_versions/RepositoryVersions/*&repository_versions/RepositoryVersions/repository_version=${version}`;
-    const response = await ambariApi.request({
-      url: url,
-      method: "GET",
-    });
-    return response.data;
-  },
   getUpgradeHistory: async function (clusterName: string) {
     const url = `/clusters/${clusterName}/upgrades?fields=Upgrade`;
     const response = await ambariApi.request({
@@ -198,35 +356,6 @@ 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({
diff --git a/ambari-web/latest/src/api/LogApi.ts b/ambari-web/latest/src/api/viewApi.tsx
similarity index 67%
rename from ambari-web/latest/src/api/LogApi.ts
rename to ambari-web/latest/src/api/viewApi.tsx
index 0011202dc7..6c9d31db7a 100644
--- a/ambari-web/latest/src/api/LogApi.ts
+++ b/ambari-web/latest/src/api/viewApi.tsx
@@ -17,16 +17,23 @@
  */
 import { ambariApi } from "./config/axiosConfig";
 
-const LogApi = {
-
-  getLogData: async function (clusterName:string, requestId:string) {
-    const url = `/clusters/${clusterName}/requests/${requestId}?fields=tasks/Tasks/command,tasks/Tasks/command_detail,tasks/Tasks/ops_display_name,tasks/Tasks/exit_code,tasks/Tasks/start_time,tasks/Tasks/end_time,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true`;
+/**
+ * Fetches a list of instance names from the Ambari API.
+ *
+ * @returns {Promise<any[]>} A promise that resolves to an array of instance names.
+ */
+const ViewApi = {
+  getInstances: async function() {
+    const url = `/views?fields=versions/ViewVersionInfo/version,versions/instances/ViewInstanceInfo,versions/*&versions/ViewVersionInfo/system=false`;
     const response = await ambariApi.request({
       url: url,
       method: "GET",
     });
-    return response.data;
-  },
+
+    
+    return response.data
+    
+  }
 };
 
-export default LogApi;
\ No newline at end of file
+export default ViewApi;
\ No newline at end of file
diff --git a/ambari-web/latest/src/api/wizardApi.ts b/ambari-web/latest/src/api/wizardApi.ts
index c737250aea..1a141bed16 100644
--- a/ambari-web/latest/src/api/wizardApi.ts
+++ b/ambari-web/latest/src/api/wizardApi.ts
@@ -64,7 +64,7 @@ const WizardApi = {
       method: "GET",
     });
     return response.data;
-  },
+  }
 };
 
 export default WizardApi;
diff --git a/ambari-web/latest/src/components/AssignMasters.tsx b/ambari-web/latest/src/components/AssignMasters.tsx
index fdb89f39c5..51f03e074b 100644
--- a/ambari-web/latest/src/components/AssignMasters.tsx
+++ b/ambari-web/latest/src/components/AssignMasters.tsx
@@ -17,42 +17,19 @@
  */
 
 import { useEffect, useReducer, useState } from "react";
-import { Row, Col, Form, Card, Button, CardBody } from "react-bootstrap";
+import { Row, Col, Form, Card, Button, CardBody, Alert } from "react-bootstrap";
+import { ChooseServicesApi } from "../api/chooseServicesApi";
+import AssignMastersApi from "../api/assignMastersApi";
 import { Utility } from "../Utils/Utility.ts";
 import { misc } from "../Utils/misc.ts";
 import Spinner from "./Spinner.tsx";
-import _, { filter, get, map, uniq } from "lodash";
+import { filter, get, map, uniq } from "lodash";
 import Select from "react-select";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
-import AssignMastersApi from "../api/AssignMastersApi.ts";
-import { ServicesResponse } from "../screens/ClusterWizard/types/StackServiceComponent.ts";
-import { ChooseServicesApi } from "../api/chooseServicesApi.ts";
-
-interface Host {
-  hostname: string;
-  cores: number;
-  memory: number;
-  components: string[];
-}
-
-interface Masters {
-  display_name: string;
-  component: string;
-  serviceId: string;
-  host_id: number;
-  hostName: string;
-  isInstalled?: boolean;
-}
-
-interface State {
-  hosts: { [key: string]: Host };
-}
-
-interface Action {
-  type: string;
-  payload: any;
-}
+import { blueprintUtils } from "../screens/ClusterWizard/utils.ts";
+import { maxToInstall, isMultipleAllowed } from "../screens/Hosts/utils.tsx";
+import { AssignMastersProps, Host, Masters, State, Action, ServicesResponse } from "../screens/ClusterWizard/types/AssignMastersTypes.ts";
 
 const initialState: State = {
   hosts: {},
@@ -77,12 +54,9 @@ function reducer(state: State, action: Action): State {
 
       // Add component to new host if newHost is not null and it doesn't already exist
       if (newHost && !updatedHosts[newHost].components.includes(component)) {
-        const index = updatedHosts[newHost].components.indexOf(component);
-        if (index !== -1) {
-          updatedHosts[newHost].components.splice(index + 1, 0, component);
-        } else {
-          updatedHosts[newHost].components.push(component);
-        }
+        updatedHosts[newHost].components.push(component);
+        // Note: We don't sort here as the sorting will be handled in the data preparation phase
+        // The components array in state.hosts is just for tracking which components are on which hosts
       }
 
       return {
@@ -95,22 +69,9 @@ function reducer(state: State, action: Action): State {
   }
 }
 
-interface AssignMastersProps {
-  STACK: string;
-  VERSION: string;
-  superMasters: any;
-  hostsList: any;
-  services: string[];
-  setCanProceed: (canProcced: boolean) => void;
-  dispatch: any;
-  installedServices?: string[];
-  parentState?:any;
-}
-
 export default function AssignMasters({
   STACK,
   VERSION,
-  superMasters,
   hostsList,
   services,
   dispatch: dispatchParent,
@@ -125,6 +86,9 @@ export default function AssignMasters({
     ) || initialState);
   const [loading, setLoading] = useState(false);
   const [mastersData, setMastersData] = useState<Masters[]>([]);
+  const [servicesAndComponents, setServicesAndComponents] = useState<ServicesResponse | null>(null);
+  const [generalErrorMessages, setGeneralErrorMessages] = useState<string[]>([]);
+  const [generalWarningMessages, setGeneralWarningMessages] = useState<string[]>([]);
   const notMasters = ["MYSQL_SERVER", "HIVE_SERVER_INTERACTIVE"];
 
   useEffect(() => {
@@ -213,6 +177,14 @@ export default function AssignMasters({
         }
       });
 
+      // Sort hosts alphabetically and create a new sorted object
+      const sortedHostsData: { [key: string]: Host } = {};
+      Object.keys(hostsData)
+        .sort()
+        .forEach(hostname => {
+          sortedHostsData[hostname] = hostsData[hostname];
+        });
+
       // validations.
       const validationPayload = {
         hosts: hostnames,
@@ -228,15 +200,21 @@ export default function AssignMasters({
         },
         services: services,
       };
-      AssignMastersApi.postValidations(validationPayload, STACK, VERSION);
-      //TODO: Check for validations response.
-
-      setCanProceed(true);
-      const servicesAndComponents: ServicesResponse =
+      
+      try {
+        const validationResponse = await AssignMastersApi.postValidations(validationPayload, STACK, VERSION);
+        updateValidationsSuccessCallback(validationResponse);
+      } catch (error) {
+        console.error('Validation API call failed:', error);
+        setCanProceed(false);
+      }
+      const servicesAndComponentsData: ServicesResponse =
         await ChooseServicesApi.getServices(STACK, VERSION);
+      
+      setServicesAndComponents(servicesAndComponentsData);
 
       // Filter components based on is_master and ensure no duplicates on a single host
-      // except for superMaster components like ZOOKEEPER_SERVER which can be on multiple hosts
+      // except for components that allow multiple instances (using isMasterAddableInstallerWizard)
       const assignedComponents = new Set<string>();
       Object.keys(hostsData).forEach((hostname) => {
         hostsData[hostname].components = hostsData[hostname].components.filter(
@@ -244,25 +222,25 @@ export default function AssignMasters({
             if(notMasters.includes(component)) {
               return false;
             }
-            const serviceComponent = servicesAndComponents.items
+            const serviceComponent = servicesAndComponentsData.items
               .flatMap((service: any) => service.components)
               .find(
                 (comp: any) =>
-                  _.get(comp, "StackServiceComponents.component_name") ===
+                  get(comp, "StackServiceComponents.component_name") ===
                   component
               );
 
-            // Allow superMaster components on multiple hosts
-            if (superMasters.includes(component)) {
-              return serviceComponent && 
-                _.get(serviceComponent, "StackServiceComponents.is_master");
+            if (!serviceComponent || !get(serviceComponent, "StackServiceComponents.is_master")) {
+              return false;
+            }
+
+            const stackComponent = get(serviceComponent, "StackServiceComponents");
+            if (isMasterAddableInstallerWizard(stackComponent)) {
+              return true;
             }
 
-            if (
-              serviceComponent &&
-              _.get(serviceComponent, "StackServiceComponents.is_master") &&
-              !assignedComponents.has(component)
-            ) {
+            // For single-instance components, ensure no duplicates
+            if (!assignedComponents.has(component)) {
               assignedComponents.add(component);
               return true;
             }
@@ -271,9 +249,9 @@ export default function AssignMasters({
         );
       });
 
-      dispatch({ type: "SET_HOSTS_DATA", payload: hostsData });
+      dispatch({ type: "SET_HOSTS_DATA", payload: sortedHostsData });
       dispatchParent({
-        hostsData,
+        hostsData: sortedHostsData,
         mastersData: getTransformedMastersData(mastersData),
         state,
       });
@@ -283,12 +261,89 @@ export default function AssignMasters({
   }, []);
   
   useEffect(() => {
+    const transformedMastersData = getTransformedMastersData(mastersData);
     dispatchParent({
-      mastersData: getTransformedMastersData(mastersData),
+      mastersData: transformedMastersData,
       state,
     });
+    validateChange(transformedMastersData)
   }, [mastersData]);
 
+  const isMasterAddableOnlyOnHA = (component: any) => {
+    return ["NAMENODE", "RESOURCEMANAGER", "RANGER_ADMIN"].includes(
+      get(component, "component_name", "")
+    );
+  }
+
+  const isNotAddableOnlyInInstall = (component: any) => {
+    return [
+      "HIVE_METASTORE",
+      "HIVE_SERVER",
+      "RANGER_KMS_SERVER",
+      "OOZIE_SERVER",
+      "TIMELINE_READER",
+      "YARN_REGISTRY_DNS",
+    ].includes(get(component, "component_name", ""));
+  };
+
+  const isMasterAddableInstallerWizard = (component: any) => {
+    return (
+      get(component, "is_master", false) &&
+      isMultipleAllowed(component) &&
+      !isMasterAddableOnlyOnHA(component) &&
+      !isNotAddableOnlyInInstall(component)
+    );
+  };
+
+  const validateChange = async (transformedMastersData: any) => {
+    try {
+      const allHostnames = map(transformedMastersData, "host_name");
+      const hostnames = uniq(allHostnames);
+      const validationResponse = await AssignMastersApi.postValidations(
+        {
+          hosts: hostnames,
+          services,
+          validate: "host_groups",
+          recommendations: getValidationRequestBody(transformedMastersData),
+        },
+        STACK,
+        VERSION,
+      );
+      updateValidationsSuccessCallback(validationResponse);
+    } catch (error) {
+      console.error('Validation API call failed:', error);
+      setCanProceed(false);
+    }
+  };
+
+  const getValidationRequestBody = (transformedMastersData: any) => {
+    const allHostnames = map(transformedMastersData, "host_name");
+    const hostnames = uniq(allHostnames);
+    const masterBlueprint = blueprintUtils.getBlueprint(
+      hostnames,
+      getSelectedMastersGroupedMapping(transformedMastersData)
+    );
+
+    return masterBlueprint;
+  };
+
+  const getSelectedMastersGroupedMapping = (transformedMastersData: any) => {
+    const hostComponentMapping: any = [];
+    transformedMastersData.forEach((selectedMaster: any) => {
+      hostComponentMapping.push({
+        hostname: selectedMaster.host_name,
+        components: selectedMaster.masterServices.map(
+          (selectedComponent: any) => {
+            return {
+              name: selectedComponent.component,
+            };
+          }
+        ),
+      });
+    });
+    return hostComponentMapping;
+  };
+
   const getTransformedMastersData = (mastersDataToBeTransformed: any) => {
     const allHostnames = map(mastersDataToBeTransformed, "hostName");
     const uniqueHostnames = uniq(allHostnames);
@@ -309,11 +364,12 @@ export default function AssignMasters({
   };
 
   useEffect(() => {
-    async function setMasterComponentsData() {
-      const servicesAndComponents: ServicesResponse =
-        await ChooseServicesApi.getServices(STACK, VERSION);
+    function setMasterComponentsData() {
+      // Only proceed if we have cached services data
+      if (!servicesAndComponents) {
+        return;
+      }
 
-      
       const mastersData: Masters[] = Object.keys(state.hosts).flatMap(
         (hostname, index) =>
           state.hosts[hostname].components
@@ -323,37 +379,41 @@ export default function AssignMasters({
               .flatMap((service: any) => service.components)
               .find(
                 (comp: any) =>
-                  _.get(comp, "StackServiceComponents.component_name") ===
+                  get(comp, "StackServiceComponents.component_name") ===
                   component
               );
             return {
-              display_name: _.get(
+              display_name: get(
                 serviceComponent,
                 "StackServiceComponents.display_name"
               ),
               component: component,
-              serviceId: _.get(
+              serviceId: get(
                 serviceComponent,
                 "StackServiceComponents.service_name"
               ),
               isInstalled: installedServices?.includes(
-                _.get(serviceComponent, "StackServiceComponents.service_name")
+                get(serviceComponent, "StackServiceComponents.service_name")
               ),
               host_id: index + 1,
               hostName: hostname,
             };
           })
-          // Sort components alphabetically by display_name
-          .sort((a, b) => (a.display_name || '').localeCompare(b.display_name || ''))
       );
+      
+      // Sort all mastersData by display_name to ensure consistent ordering
+      const sortedMastersData = mastersData.sort((a, b) => 
+        (a.display_name || a.component).localeCompare(b.display_name || b.component)
+      );
+      
       dispatchParent({
-        mastersData: getTransformedMastersData(mastersData),
+        mastersData: getTransformedMastersData(sortedMastersData),
         state,
       });
-      setMastersData(mastersData);
+      setMastersData(sortedMastersData);
     }
     setMasterComponentsData();
-  }, [state.hosts]);
+  }, [state.hosts, servicesAndComponents]);
 
   const handleComponentChange = (
     component: string,
@@ -367,11 +427,36 @@ export default function AssignMasters({
       });
     }
   };
+  const getMaxNumberOfMasters = (componentName: string) => {
+    if (!servicesAndComponents) return 1;
+    
+    const serviceComponent = servicesAndComponents.items
+      .flatMap((service: any) => service.components)
+      .find(
+        (comp: any) =>
+          get(comp, "StackServiceComponents.component_name") === componentName
+      );
+
+    if (!serviceComponent) return 1;
+
+    const stackComponent = get(serviceComponent, "StackServiceComponents");
+    const maxToInstallValue = maxToInstall(stackComponent);
+    const hostsNumber = Object.keys(state.hosts).length;
+    
+    return Math.min(maxToInstallValue, hostsNumber);
+  };
 
   const handleAddComponent = (component: string) => {
+    const maxNumMasters = getMaxNumberOfMasters(component);
+    const currentMasters = mastersData.filter(master => master.component === component);
+    
+    if (currentMasters.length >= maxNumMasters) {
+      return false;
+    }
+
     // Find the first host that doesn't already have this component
     const availableHost = Object.keys(state.hosts).find((hostname) => {
-      return !_.get(state.hosts[hostname], "components", []).includes(
+      return !get(state.hosts[hostname], "components", []).includes(
         component as never
       );
     });
@@ -381,16 +466,89 @@ export default function AssignMasters({
         type: "UPDATE_COMPONENT_HOST",
         payload: { component, oldHost: null, newHost: availableHost, state },
       });
+      return true;
     }
+    return false;
   };
 
   const handleRemoveComponent = (component: string, hostname: string) => {
+    const currentMasters = mastersData.filter(master => master.component === component);
+    
+    // Don't allow removal if only one instance exists
+    if (currentMasters.length <= 1) {
+      return false;
+    }
+
     dispatch({
       type: "UPDATE_COMPONENT_HOST",
       payload: { component, oldHost: hostname, newHost: null, state },
     });
+    return true;
   };
 
+  /**
+  * Remove validation messages for components which are already installed
+  */
+  const filterNotInstalledComponents = (validationData: any) => {
+    return validationData.resources[0].items.filter((item: any) => {
+      const host = state.hosts[item.host];
+      return !host || !host.components.includes(item['component-name']);
+    });
+  };
+
+  /**
+   * Process validation response
+   */
+  const updateValidationsSuccessCallback = (data: any) => {
+    const newGeneralErrorMessages: string[] = [];
+    const newGeneralWarningMessages: string[] = [];
+    
+    // Clear existing validation messages from mastersData
+    const updatedMastersData = mastersData.map(master => {
+      const { warnMessage, errorMessage, ...rest } = master;
+      return {
+        ...rest,
+        warnMessage: "",
+        errorMessage: "",
+      };
+    });
+    
+    let anyErrors = false;
+
+    // Process validation data - filter out installed components
+    const validationData = filterNotInstalledComponents(data);
+    validationData
+      .filter((item: any) => item.type === 'host-component')
+      .forEach((item: any) => {
+        // Find the master component that matches this validation item
+        const masterIndex = updatedMastersData.findIndex(master => 
+          master.component === item['component-name'] && 
+          master.hostName === item.host
+        );
+        
+        if (masterIndex !== -1) {
+          if (item.level === 'ERROR') {
+            anyErrors = true;
+            generalErrorMessages.push(item.message);
+            updatedMastersData[masterIndex] = {
+              ...updatedMastersData[masterIndex],
+              errorMessage: item.message
+            };
+          } else if (item.level === 'WARN') {
+            generalWarningMessages.push(item.message);
+            updatedMastersData[masterIndex] = {
+              ...updatedMastersData[masterIndex],
+              warnMessage: item.message
+            };
+          }
+        }
+      });
+
+    setGeneralErrorMessages(newGeneralErrorMessages);
+    setGeneralWarningMessages(newGeneralWarningMessages);
+
+    setCanProceed(!anyErrors);
+  };
 
   return (
     <>
@@ -398,6 +556,30 @@ export default function AssignMasters({
       <p className="step-description">
         Assign master components to hosts you want to run them on.
       </p>
+      
+      {/* Display general validation messages */}
+      {generalErrorMessages.length > 0 && (
+        <Alert variant="danger" className="mb-3">
+          <strong>Validation Errors:</strong>
+          <ul className="mb-0 mt-2">
+            {generalErrorMessages.map((message, index) => (
+              <li key={index}>{message}</li>
+            ))}
+          </ul>
+        </Alert>
+      )}
+      
+      {generalWarningMessages.length > 0 && (
+        <Alert variant="warning" className="mb-3">
+          <strong>Validation Warnings:</strong>
+          <ul className="mb-0 mt-2">
+            {generalWarningMessages.map((message, index) => (
+              <li key={index}>{message}</li>
+            ))}
+          </ul>
+        </Alert>
+      )}
+      
       {loading ? (
         <Spinner />
       ) : (
@@ -405,57 +587,18 @@ export default function AssignMasters({
           <CardBody>
             <Row>
               <Col md={8}>
-                {(() => {
-                  // Get all components from all hosts
-                  const allComponentsWithHosts: Array<{component: string, hostname: string}> = [];
-                  
-                  // Collect all components with their assigned hosts
-                  Object.keys(state.hosts).forEach(hostname => {
-                    state.hosts[hostname].components.forEach(component => {
-                      allComponentsWithHosts.push({
-                        component,
-                        hostname
-                      });
-                    });
-                  });
-                  
-                  // Get display names for all components
-                  const componentDisplayNames: { [key: string]: string } = {};
-                  allComponentsWithHosts.forEach(({component, hostname}) => {
-                    const serviceComponent = mastersData.find(m => 
-                      m.component === component && m.hostName === hostname
-                    );
-                    if (serviceComponent) {
-                      // Use component as key to ensure uniqueness
-                      const key = `${component}-${hostname}`;
-                      componentDisplayNames[key] = serviceComponent.display_name || component;
-                    }
-                  });
-                  
-                  // Sort all components by their display names
-                  return allComponentsWithHosts
-                    // Filter out installed components
-                    .filter(({component, hostname}) => {
-                      const matchingMasterForInstall = mastersData.find(m => 
-                        m.component === component && m.hostName === hostname && m.isInstalled
-                      );
-                      return !(matchingMasterForInstall && matchingMasterForInstall.isInstalled);
-                    })
-                    // Sort by display name
-                    .sort((a, b) => {
-                      const keyA = `${a.component}-${a.hostname}`;
-                      const keyB = `${b.component}-${b.hostname}`;
-                      const displayNameA = componentDisplayNames[keyA] || a.component;
-                      const displayNameB = componentDisplayNames[keyB] || b.component;
-                      return displayNameA.localeCompare(displayNameB);
-                    })
-                    // Render each component
-                    .map(({component, hostname}) => {
-                      const key = `${component}-${hostname}`;
-                      const displayName = componentDisplayNames[key] || component;
-                      
-                      return (
-                        <Row key={`${hostname}-${component}`} className="mb-3">
+                {/* Render components using pre-sorted mastersData */}
+                {mastersData
+                  // Filter out installed components
+                  .filter((master) => !master.isInstalled)
+                  // Render each component
+                  .map((master) => {
+                    const { component, hostName: hostname, display_name, errorMessage, warnMessage } = master;
+                    const displayName = display_name || component;
+                    
+                    return (
+                      <div key={`${hostname}-${component}`}>
+                        <Row className="mb-3">
                           <Col xs={4} className="text-end mt-3">
                             <Form.Label className="fw-100">
                               {displayName}:
@@ -465,7 +608,7 @@ export default function AssignMasters({
                             <Select
                               id={`select-${component}`}
                               value={{ label: hostname, value: hostname }}
-                              onChange={(selectedOption: any) => {
+                              onChange={(selectedOption) => {
                                 if (selectedOption) {
                                   handleComponentChange(
                                     component,
@@ -478,7 +621,7 @@ export default function AssignMasters({
                                 .filter(
                                   (host) =>
                                     host === hostname ||
-                                    !_.get(
+                                    !get(
                                       state.hosts[host],
                                       "components",
                                       []
@@ -492,39 +635,96 @@ export default function AssignMasters({
                             />
                           </Col>
                           <Col xs={4} className="d-flex align-items-center">
-                            {superMasters.includes(component) && (
-                              <>
-                                {Object.keys(state.hosts).some(
-                                  (host) =>
-                                    !state.hosts[host].components.includes(
-                                      component
-                                    )
-                                ) ? (
-                                  <Button
-                                    variant="success"
-                                    size="sm"
-                                    onClick={() => handleAddComponent(component)}
-                                  >
-                                    <FontAwesomeIcon icon={faPlus} />
-                                  </Button>
-                                ) : (
-                                  <Button
-                                    variant="success"
-                                    size="sm"
-                                    onClick={() =>
-                                      handleRemoveComponent(component, hostname)
-                                    }
-                                  >
-                                    <FontAwesomeIcon icon={faMinus} />
-                                  </Button>
-                                )}
-                              </>
-                            )}
+                            {(() => {
+                              // Get the service component to check if it's addable in installer wizard
+                              const serviceComponent = servicesAndComponents?.items
+                                .flatMap((service: any) => service.components)
+                                .find(
+                                  (comp: any) =>
+                                    get(comp, "StackServiceComponents.component_name") === component
+                                );
+
+                              if (!serviceComponent) return null;
+                              const stackComponent = get(serviceComponent, "StackServiceComponents");
+                              const isAddableInInstallerWizard = isMasterAddableInstallerWizard(stackComponent);
+                              if (!isAddableInInstallerWizard) {
+                                return null;
+                              }
+
+                              const componentCount = Object.keys(state.hosts).filter(hostname => 
+                                state.hosts[hostname].components.includes(component)
+                              ).length;
+                              
+                              const totalHosts = Object.keys(state.hosts).length;
+                              
+                              // Logic based on Ember.js implementation:
+                              // 1. Show add control if current count < max allowed masters
+                              // 2. Show remove control if current count > 1 (for non-installed components)
+                              // 3. Respect the maxToInstall cardinality from stack definition
+                              const maxNumMasters = getMaxNumberOfMasters(component);
+                              let showPlusButton = false;
+                              let showMinusButton = false;
+                              
+                              // Show add button if we haven't reached the maximum
+                              if (componentCount < maxNumMasters) {
+                                showPlusButton = true;
+                              }
+                              
+                              // Show remove button if we have more than 1 instance
+                              if (componentCount > 1) {
+                                showMinusButton = true;
+                              }
+                              
+                              return (
+                                <div className="d-flex gap-1">
+                                  {showPlusButton && (
+                                    <Button
+                                      variant="success"
+                                      size="sm"
+                                      className="h15"
+                                      onClick={() => handleAddComponent(component)}
+                                      title={`Add ${component} (${componentCount}/${totalHosts})`}
+                                    >
+                                      <FontAwesomeIcon icon={faPlus} />
+                                    </Button>
+                                  )}
+                                  {showMinusButton && (
+                                    <Button
+                                      variant="secondary"
+                                      size="sm"
+                                      onClick={() => handleRemoveComponent(component, hostname)}
+                                      title={`Remove ${component} (${componentCount}/${totalHosts})`}
+                                    >
+                                      <FontAwesomeIcon icon={faMinus} />
+                                    </Button>
+                                  )}
+                                </div>
+                              );
+                            })()}
                           </Col>
                         </Row>
-                      );
-                    });
-                })()}
+                        {/* Display validation messages */}
+                        {errorMessage && (
+                          <Row className="mb-2">
+                            <Col xs={12}>
+                              <Alert variant="danger" className="py-2 small">
+                                <strong>Error:</strong> {errorMessage}
+                              </Alert>
+                            </Col>
+                          </Row>
+                        )}
+                        {warnMessage && (
+                          <Row className="mb-2">
+                            <Col xs={12}>
+                              <Alert variant="warning" className="py-2 small">
+                                <strong>Warning:</strong> {warnMessage}
+                              </Alert>
+                            </Col>
+                          </Row>
+                        )}
+                      </div>
+                    );
+                  })}
               </Col>
 
               <Col md={4}>
diff --git a/ambari-web/latest/src/components/AssignMastersAddable.tsx b/ambari-web/latest/src/components/AssignMastersAddable.tsx
new file mode 100644
index 0000000000..9b8a4fc082
--- /dev/null
+++ b/ambari-web/latest/src/components/AssignMastersAddable.tsx
@@ -0,0 +1,1670 @@
+/**
+ * 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 { useContext, useEffect, useRef, useState } from "react";
+import { AppContext } from "../store/context";
+import { HostsApi } from "../api/hostsApi";
+import useHostComponents from "../screens/ClusterWizard/hooks/useHostComponents";
+import Spinner from "./Spinner";
+import {
+  cloneDeep,
+  filter,
+  find,
+  flatten,
+  forEach,
+  get,
+  isEmpty,
+  map,
+  merge,
+  reject,
+  set,
+  some,
+  sortBy,
+  uniq,
+} from "lodash";
+import { groupPropertyValues } from "../Utils/dataUtils";
+import Select from "react-select";
+import AssignMastersApi from "../api/assignMastersApi";
+import { isShownOnAddServiceAssignMasterPage, role } from "../Utils/Utility";
+import { displayOrder } from "../screens/ClusterWizard/constants";
+import {
+  isMasterAddableInstallerWizard,
+  maxToInstall,
+} from "../screens/Hosts/utils";
+import { Badge, Button, Col, Row, Stack, Alert } from "react-bootstrap";
+import { misc } from "../Utils/misc";
+import classNames from "classnames";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
+
+type AssignMastersAddableProps = {
+  services: string[];
+  mastersToCreate?: string[];
+  mastersToShow?: string[];
+  mastersToMove?: string[];
+  mastersToAdd?: string[];
+  showCurrentPrefix?: string[];
+  showAdditionalPrefix?: string[];
+  mastersAddableInHA?: string[];
+  showInstalledMastersFirst?: boolean;
+  dispatch: any;
+  isInstallFlow?: boolean;
+  showJournalNode?: boolean;
+  wizardName?: string;
+  servicesData?: any;
+};
+
+function AssignMastersAddable({
+  services,
+  mastersToCreate = [],
+  mastersToShow = [],
+  mastersToMove = [],
+  mastersToAdd = [],
+  showCurrentPrefix = [],
+  showAdditionalPrefix = [],
+  mastersAddableInHA = [],
+  showInstalledMastersFirst = false,
+  isInstallFlow = false,
+  dispatch,
+  showJournalNode = false,
+  wizardName = "",
+  servicesData = {},
+}: AssignMastersAddableProps) {
+  const [hosts, setHosts] = useState([]);
+  const {
+    clusterName,
+    cluster: { versionNum, stack },
+  } = useContext(AppContext);
+  const [recommendations, setRecommendations] = useState<any>([]);
+  const [recommededHostsForComponents, setRecommendedHostsForComponents] =
+    useState<any>({});
+  const { hostComponents: serviceHostComponents, serviceComponents } =
+    useHostComponents(services, showJournalNode);
+  const [selectedServicesMasters, setSelectedServicesMasters] = useState<any>(
+    []
+  );
+  const [inferredMasterHosts, setInferredMasterHosts] = useState([]);
+  const [inferredSlaveHosts, setInferredSlaveHosts] = useState([]);
+  const [addableMasters, setAddableMasters] = useState<any>([]);
+  const [servicesMasters, setServicesMasters] = useState<any>([]);
+  const [masterHostsMapping, setMasterHostsMapping] = useState<any>([]);
+  const [inferredMasterComponents, setInferredMasterComponents] = useState<any>(
+    []
+  );
+
+  // Function to get warning message for hosts not running master services
+  function getHostWarningMessage() {
+    if (!hosts.length || !inferredMasterHosts.length) return null;
+    
+    // Get all hosts in the cluster
+    const allHostNames = hosts.map((host: any) => host.Hosts.host_name);
+    
+    // Get hosts that are currently running master services from inferredMasterHosts
+    // These are the hosts that actually have installed master components
+    const currentHostsRunningMasters = uniq(
+      inferredMasterHosts
+        .filter((masterHost: any) => masterHost.isInstalled)
+        .map((masterHost: any) => masterHost.hostName)
+    );
+    
+    // Get hosts that will be running master services after the move operation
+    // This includes both current hosts and new target hosts from moves
+    const futureHostsRunningMasters = uniq([
+      ...currentHostsRunningMasters,
+      // Add target hosts from move operations
+      ...addableMasters
+        .filter((master: any) => master.movedHost) // Only moving components
+        .map((master: any) => master.movedHost),
+      // Add any other selected hosts that will have masters
+      ...addableMasters
+        .filter((master: any) => !master.isInstalled) // New components
+        .map((master: any) => master.selectedHost)
+    ]);
+    
+    // Find hosts not running master services (considering future state)
+    const hostsNotRunningMasters = allHostNames.filter(
+      (hostName: string) => !futureHostsRunningMasters.includes(hostName)
+    );
+
+    if (hostsNotRunningMasters.length > 0) {
+      return `${hostsNotRunningMasters.length} hosts not running master services`;
+    }
+    
+    return null;
+  }
+
+
+  // Function to enhance inferred master hosts with isMoving information
+  function getEnhancedInferredMasterHosts() {
+    return inferredMasterHosts.map((masterHost: any) => {
+      // Find matching component in selectedServicesMasters that has movedHost and isMoving
+      const matchingServiceMaster = selectedServicesMasters.find((serviceMaster: any) => 
+        serviceMaster.component_name === masterHost.component && 
+        serviceMaster.hostName === masterHost.hostName &&
+        serviceMaster.movedHost &&
+        serviceMaster.isMoving === true
+      );
+      
+      // Find matching component in addableMasters that has movedHost and isMoving
+      const matchingAddableMaster = addableMasters.find((addableMaster: any) => 
+        addableMaster.component_name === masterHost.component && 
+        addableMaster.hostName === masterHost.hostName &&
+        addableMaster.movedHost &&
+        addableMaster.isMoving === true
+      );
+
+      const matchingComponent = matchingServiceMaster || matchingAddableMaster;
+
+      return {
+        ...masterHost,
+        isMoving: !!matchingComponent,
+        movedHost: matchingComponent ? matchingComponent.movedHost : undefined
+      };
+    });
+  }
+  const initiallyLoaded = useRef(false);
+  const selectedServicesMastersRef = useRef<any>([]);
+  const servicesMastersRef = useRef<any>([]);
+  const [, setComponentToRebalance] = useState("");
+  const [, setLastChangedComponent] = useState("");
+  const [, setRebalanceHostCounter] = useState(0);
+  
+  useEffect(() => {
+    const flattenedHostComponents = flatten(
+      map(serviceHostComponents, "host_components")
+    );
+    const flattenedHostRoles = flatten(
+      map(flattenedHostComponents, "HostRoles")
+    );
+    const groupedHosts = groupPropertyValues(flattenedHostRoles, "host_name");
+    const hostComponentsRoles = flatten(
+      map(serviceHostComponents, "host_components")
+    );
+    const hostComponents = flatten(map(hostComponentsRoles, "HostRoles"));
+    const masterComponentHostsToDispatch = flatten([
+      ...getEnhancedInferredMasterHosts(),
+      filter(inferredMasterComponents, ["isInstalled", false]),
+    ]);
+    
+    dispatch({
+      masterHostsMapping,
+      hosts: groupedHosts,
+      masterHosts: inferredMasterHosts,
+      enhancedMasterHosts: getEnhancedInferredMasterHosts(),
+      slaveHosts: inferredSlaveHosts,
+      mastersData: masterHostsMapping,
+      masterComponentHosts: masterComponentHostsToDispatch,
+      slaveComponentHosts: null,
+      hostComponents,
+    });
+  }, [masterHostsMapping]);
+
+  function createComponentInstallationObject(
+    fullComponent: any,
+    hostName: string,
+    savedComponent?: any
+  ) {
+    fullComponent.component_name =
+      fullComponent.componentName || fullComponent.component_name;
+    fullComponent.component =
+      fullComponent.componentName || fullComponent.component_name;
+    const componentName: any = fullComponent.component_name,
+      resultingHostName = savedComponent ? savedComponent.hostName : hostName;
+    let componentObj: any = {};
+    componentObj.component_name = componentName;
+    componentObj.component = componentName;
+    componentObj.display_name = role(fullComponent.component_name, false);
+    componentObj.serviceId = fullComponent.service_name;
+    componentObj.isServiceCoHost = !mastersToMove.includes(
+      componentName as never
+    );
+    componentObj.selectedHost = resultingHostName;
+    componentObj.hostName = resultingHostName;
+    componentObj.isInstalled = savedComponent
+      ? savedComponent.isInstalled ||
+        !mastersToCreate.includes(fullComponent.component_name as never)
+      : false;
+    //Check for namenode federation
+    // if (this.get('content.controllerName') === 'reassignMasterController' && componentName === 'NAMENODE' && App.get('hasNameNodeFederation')) {
+    //   componentObj.nameSpace = App.HostComponent.find(`${componentName}_${resultingHostName}`).get('haNameSpace');
+    // }
+    return componentObj;
+  }
+
+  function getHostForMaster(master: any, allMasters: any[]) {
+    const masterHostList: any = [];
+    allMasters.forEach((component: any) => {
+      if (component.component_name === master) {
+        masterHostList.push(component.selectedHost);
+      }
+    });
+    const recommendedHostsForMaster =
+      recommededHostsForComponents[master] || [];
+    for (let k = 0; k < recommendedHostsForMaster.length; k++) {
+      if (!masterHostList.includes(recommendedHostsForMaster[k])) {
+        return recommendedHostsForMaster[k];
+      }
+    }
+    let usedHosts = map(
+      filter(allMasters, ["component_name", master]),
+      "selectedHost"
+    );
+    var allHosts = hosts;
+    for (var i = 0; i < allHosts.length; i++) {
+      if (!usedHosts.includes(get(allHosts[i], "Hosts.host_name"))) {
+        return get(allHosts[i], "Hosts.host_name");
+      }
+    }
+
+    return false;
+  }
+
+  function masterHostMapping() {
+    let mapping: any = [],
+      mappingObject,
+      mappedHosts,
+      hostObj: any;
+    const allHosts = [
+      ...map(selectedServicesMasters, "selectedHost"),
+      ...map(selectedServicesMasters, "movedHost"),
+    ];
+    mappedHosts = uniq(allHosts);
+    mappedHosts.forEach(function (item) {
+      hostObj = find(hosts, ["Hosts.host_name", item]);
+      // User may input invalid host name (this is handled in hostname checker). Here we just skip it
+      if (!hostObj) return;
+      let masterServices = filter(
+        selectedServicesMasters,
+        (masterService: any) => {
+          return masterService.movedHost
+            ? masterService.movedHost === item
+            : masterService.selectedHost === item;
+        }
+      );
+      let masterServicesToDisplay: any = [];
+      uniq(map(masterServices, "display_name")).forEach(function (n) {
+        masterServicesToDisplay.push(find(masterServices, ["display_name", n]));
+      });
+      mappingObject = {
+        host_name: item,
+        hostInfo: hostObj.host_info,
+        masterServices: masterServices,
+        masterServicesToDisplay: masterServicesToDisplay,
+      };
+
+      mapping.push(mappingObject);
+    });
+    setMasterHostsMapping(mapping);
+  }
+
+  function sortMasterComponents(masters: any[]) {
+    return [].concat(
+      filter(masters, ["isInstalled", true]) as any,
+      filter(masters, ["isInstalled", false]) as any
+    );
+  }
+
+  function servicesMastersToShow() {
+    let result: any = [];
+    if (!mastersToShow.length) {
+      result = servicesMasters;
+    } else {
+      mastersToShow.forEach(function (master) {
+        result = result.concat(
+          filter(servicesMasters, ["component_name", master])
+        );
+      });
+    }
+    if (showInstalledMastersFirst) {
+      result = sortMasterComponents(result);
+    }
+
+    const installedServices = map(
+      filter(
+        getFlattenedcomponents(),
+        (component: any) => servicesData[component.service_name]?.installed
+      ),
+      "service_name"
+    );
+
+    for (const item of result) {
+      const stackComponent =
+        find(getFlattenedcomponents(), [
+          "component_name",
+          item.component_name,
+        ]) || {};
+      const isMasterWithMultipleInstances = get(
+        stackComponent,
+        "isMasterWithMultipleInstances",
+        false
+      );
+      const showControl =
+        !installedServices.includes(get(stackComponent, "service_name", "")) ||
+        mastersAddableInHA.includes(item.component_name);
+
+      // PRIMARY RULE: In move/reassign scenarios, NEVER show add/remove controls for ANY component
+      // This is the most important rule and overrides all other logic
+      if (mastersToMove.length > 0) {
+        set(item, "showRemoveControl", false);
+        set(item, "showAddControl", false);
+      }
+      // In reassign/move scenarios, installed components should NEVER show add/remove controls
+      // This is a secondary rule for additional safety
+      else if (item.isInstalled && mastersToMove.includes(item.component_name)) {
+        set(item, "showRemoveControl", false);
+        set(item, "showAddControl", false);
+      }
+      // Special handling for NameNode Federation - never show controls for additional NameNodes
+      // This matches the ui version behavior where NAMENODE controls are not shown in federation wizard
+      else if (
+        item.component_name === "NAMENODE" &&
+        showAdditionalPrefix.includes("NAMENODE") &&
+        !item.isInstalled
+      ) {
+        set(item, "showRemoveControl", false);
+        set(item, "showAddControl", false);
+      }
+      // Special handling for NameNode in HA mode - never show controls
+      else if (
+        item.component_name === "NAMENODE" &&
+        mastersToShow.includes("NAMENODE") &&
+        mastersToShow.includes("JOURNALNODE")
+      ) {
+        set(item, "showRemoveControl", false);
+        set(item, "showAddControl", false);
+      }
+      // Special handling for ResourceManager in HA mode - never show controls (matching Ember)
+      else if (
+        item.component_name === "RESOURCEMANAGER" &&
+        mastersToShow.includes("RESOURCEMANAGER") &&
+        mastersToShow.length === 1
+      ) {
+        set(item, "showRemoveControl", false);
+        set(item, "showAddControl", false);
+      } else if (item.isInstalled) {
+        set(item, "showRemoveControl", false);
+        set(item, "showAddControl", false);
+      } else if (isMasterWithMultipleInstances && showControl) {
+        // For non-installed multiple instance masters, show add/remove based on count
+        const mastersCount = filter(result, [
+          "component_name",
+          item.component_name,
+        ]).length;
+        set(item, "showRemoveControl", mastersCount > 1);
+        set(
+          item,
+          "showAddControl",
+          mastersCount < getMaxNumberOfMasters(item.component_name)
+        );
+      } else {
+        // Default to no controls for components not in mastersAddableInHA
+        set(item, "showRemoveControl", false);
+        set(item, "showAddControl", false);
+      }
+      set(item, "isMoving", mastersToMove.includes(item.component));
+    }
+
+    // Special handling for JournalNodes - apply the Ember logic exactly
+    // This applies to both NameNode HA wizard and Manage JournalNodes wizard
+    if (mastersToShow.includes("JOURNALNODE") && mastersToMove.length === 0) {
+      const JOURNALNODES_COUNT_MINIMUM = 3;
+      const journalNodes = filter(result, ["component_name", "JOURNALNODE"]);
+      const maxNumMasters = getMaxNumberOfMasters("JOURNALNODE");
+      
+      // TLHASD-1164: Implement exact Ember logic from showHideJournalNodesAddRemoveControl
+      // Remove control is only shown when there are MORE than minimum required JournalNodes
+      const showRemoveControl = journalNodes.length > JOURNALNODES_COUNT_MINIMUM;
+      const showAddControl = journalNodes.length < maxNumMasters;
+
+      // Set all JournalNodes to not show add control initially
+      journalNodes.forEach(function (item: any) {
+        set(item, "showAddControl", false);
+        set(item, "showRemoveControl", showRemoveControl);
+      });
+
+      // Only the last JournalNode should show add control (matching Ember: jns.set('lastObject.showAddControl', showAddControl))
+      if (journalNodes.length > 0) {
+        set(
+          journalNodes[journalNodes.length - 1],
+          "showAddControl",
+          showAddControl
+        );
+      }
+    }
+
+    setAddableMasters(result);
+  }
+
+  function getServiceByMaster(master: any) {
+    const allComponents = flatten(
+      map(
+        flatten(map(serviceComponents, "components")),
+        "StackServiceComponents"
+      )
+    );
+    const mappedService = find(allComponents, ["component_name", master]);
+    return get(mappedService, "service_name", "");
+  }
+
+  function addNewMasters(masterComponents: any) {
+    if (!mastersToAdd.length && isInstallFlow) {
+      const notMasters = ["MYSQL_SERVER", "HIVE_SERVER_INTERACTIVE"];
+      const allMasterComponents = map(
+        filter(flatten(map(serviceComponents, "components")), [
+          "StackServiceComponents.is_master",
+          true,
+        ]),
+        "StackServiceComponents.component_name"
+      );
+      const installedMasters: string[] = map(
+        serviceHostComponents,
+        "ServiceComponentInfo.component_name"
+      );
+      let missingMasters = filter(
+        allMasterComponents,
+        function (masterName: string) {
+          return (
+            !installedMasters.includes(masterName) &&
+            !notMasters.includes(masterName)
+          );
+        }
+      );
+      let updatedMissingMasters = [];
+      if (wizardName === "addService") {
+        for (const master of missingMasters) {
+          const serviceOfMaster = getServiceByMaster(master);
+          if (servicesData[serviceOfMaster]?.installed === false) {
+            updatedMissingMasters.push(master);
+          }
+        }
+      }
+      mastersToAdd =
+        wizardName === "addService" ? updatedMissingMasters : missingMasters;
+    }
+    mastersToAdd.forEach(function (masterName: string) {
+      var toBeAddedNumber = mastersToAdd.filter(function (name) {
+          return name === masterName;
+        }).length,
+        alreadyAddedNumber = reject(
+          filter(masterComponents, ["component_name", masterName]),
+          "isInstalled"
+        ).length;
+      if (toBeAddedNumber > alreadyAddedNumber) {
+        var hostName = getHostForMaster(masterName, masterComponents),
+          serviceName = getServiceByMaster(masterName);
+        masterComponents.push(
+          createComponentInstallationObject(
+            {
+              componentName: masterName,
+              serviceName: serviceName,
+            },
+            hostName
+          )
+        );
+      }
+    });
+    return masterComponents;
+  }
+
+  function sortComponentsByServiceName(components: any) {
+    const componentsOrderForService: any = {
+      HAWQ: ["HAWQMASTER", "HAWQSTANDBY"],
+    };
+    let indexForUnordered = Math.max(displayOrder.length, components.length);
+    return components.sort(function (a: any, b: any) {
+      if (
+        a.serviceId === b.serviceId &&
+        a.serviceId in componentsOrderForService
+      )
+        return (
+          componentsOrderForService[a.serviceId].indexOf(a.component_name) -
+          componentsOrderForService[b.serviceId].indexOf(b.component_name)
+        );
+      var aValue =
+        displayOrder.indexOf(a.serviceId) != -1
+          ? displayOrder.indexOf(a.serviceId)
+          : indexForUnordered;
+      var bValue =
+        displayOrder.indexOf(b.serviceId) != -1
+          ? displayOrder.indexOf(b.serviceId)
+          : indexForUnordered;
+      return aValue - bValue;
+    });
+  }
+
+  async function renderComponents(masterComponents: any) {
+    let result: any = [];
+    //@ts-ignore
+    let serviceComponentId, previousComponentName;
+    addNewMasters(masterComponents);
+    //@ts-ignore
+    const allComponents = flatten(
+      map(
+        flatten(map(serviceComponents, "components")),
+        "StackServiceComponents"
+      )
+    );
+    masterComponents.forEach(function (item: any) {
+      const allComponents = flatten(
+        map(
+          flatten(map(serviceComponents, "components")),
+          "StackServiceComponents"
+        )
+      );
+      const masterComponent: any = find(allComponents, [
+        "component_name",
+        item.component_name,
+      ]);
+      setInferredMasterComponents(masterComponents);
+      if (masterComponent) {
+        let componentObj = { ...item };
+        if (item.nameSpace) {
+          componentObj = {
+            allMasters: result,
+            namespace: (function () {
+              // Todo: Logic to get namespace
+            })(),
+          };
+        }
+        let showRemoveControl;
+        if (masterComponent.isMasterWithMultipleInstances) {
+          showRemoveControl =
+            filter(masterComponents, function (masterComponent: any) {
+              masterComponent.component_name === item.component_name &&
+                !masterComponent.isInstalled;
+            }).length > 1;
+          previousComponentName = item.component_name;
+          set(
+            componentObj,
+            "serviceComponentId",
+            filter(result, ["component_name", item.component_name]).length + 1
+          );
+          if (componentObj.isInstalled) {
+            set(componentObj, "showRemoveControl", false);
+          } else {
+            set(componentObj, "showRemoveControl", showRemoveControl);
+          }
+        }
+        set(componentObj, "isHostNameValid", true);
+        // Handle HA state display for ResourceManager (matching Ember logic)
+        if (
+          item.component_name === "RESOURCEMANAGER" &&
+          mastersToShow.includes("RESOURCEMANAGER")
+        ) {
+          const flattenedHostComponents = flatten(
+            map(serviceHostComponents, "host_components")
+          );
+          const flattenedHostRoles = flatten(
+            map(flattenedHostComponents, "HostRoles")
+          );
+          const hostComponent = find(
+            flattenedHostRoles,
+            (hc: any) =>
+              hc.component_name === "RESOURCEMANAGER" &&
+              hc.host_name === item.selectedHost
+          );
+          const haState = get(hostComponent, "ha_state", "");
+
+          if (haState === "ACTIVE") {
+            set(componentObj, "showCurrentPrefix", false);
+            set(componentObj, "showAdditionalPrefix", false);
+            set(componentObj, "display_name", "Active ResourceManager");
+          } else if (
+            haState === "STANDBY" ||
+            (!item.isInstalled && haState !== "ACTIVE")
+          ) {
+            set(componentObj, "showCurrentPrefix", false);
+            set(componentObj, "showAdditionalPrefix", false);
+            set(
+              componentObj,
+              "display_name",
+              item.isInstalled
+                ? "Standby ResourceManager"
+                : "Additional ResourceManager"
+            );
+          } else {
+            // Fallback to original logic
+            set(
+              componentObj,
+              "showCurrentPrefix",
+              showCurrentPrefix.includes(item.component_name as never) &&
+                item.isInstalled
+            );
+            set(
+              componentObj,
+              "showAdditionalPrefix",
+              showAdditionalPrefix.includes(item.component_name as never) &&
+                !item.isInstalled
+            );
+          }
+        } else {
+          set(
+            componentObj,
+            "showCurrentPrefix",
+            showCurrentPrefix.includes(item.component_name as never) &&
+              item.isInstalled
+          );
+          set(
+            componentObj,
+            "showAdditionalPrefix",
+            showAdditionalPrefix.includes(item.component_name as never) &&
+              !item.isInstalled
+          );
+        }
+        if (mastersToMove.includes(item.component_name as never)) {
+          set(componentObj, "isInstalled", false);
+        }
+        result.push(componentObj);
+      }
+    });
+    result = sortComponentsByServiceName(result);
+    setSelectedServicesMasters(result);
+    setServicesMasters(result);
+    setInferredMasterComponents(result);
+    selectedServicesMastersRef.current = result;
+    servicesMastersRef.current = result;
+
+    // JournalNode controls will be handled in servicesMastersToShow()
+  }
+
+  function createComponentInstallationObjects() {
+    let stackMasterComponentsMap: any = {},
+      resultComponents: any = [],
+      multipleComponentHasBeenAdded: any = {},
+      hostGroupsMap: any = {};
+
+    const allComponents = flatten(
+      map(
+        flatten(map(serviceComponents, "components")),
+        "StackServiceComponents"
+      )
+    );
+    const journalNode: any = find(allComponents, [
+      "component_name",
+      "JOURNALNODE",
+    ]);
+    if (journalNode && showJournalNode) {
+      journalNode.is_master = true;
+    }
+    const masterComponents = map(
+      filter(allComponents, ["is_master", true]),
+      "component_name"
+    );
+    const slaveComponents = map(
+      filter(allComponents, ["component_category", "SLAVE"]),
+      "component_name"
+    );
+    serviceHostComponents.forEach(function (serviceComponent: any) {
+      serviceComponent.host_components.map((hostComponent: any) => {
+        set(
+          hostComponent,
+          "HostRoles.service_name",
+          get(serviceComponent, "ServiceComponentInfo.service_name")
+        );
+      });
+    });
+    const flattenedHostComponents = flatten(
+      map(serviceHostComponents, "host_components")
+    );
+    const flattenedHostRoles = flatten(
+      map(flattenedHostComponents, "HostRoles")
+    );
+    let masterHosts: any = [];
+    let slaveHosts: any = [];
+    for (const masterComponent of masterComponents) {
+      const hostsWithMasterComponent = filter(flattenedHostRoles, [
+        "component_name",
+        masterComponent,
+      ]);
+
+      const transformedMasterHosts = map(
+        hostsWithMasterComponent,
+        function (masterComponentHost: any) {
+          return {
+            component: masterComponent,
+            hostName: masterComponentHost.host_name,
+            isInstalled: true,
+            serviceId: get(masterComponentHost, "service_name", ""),
+            display_name: get(masterComponentHost, "display_name", ""),
+          };
+        }
+      );
+      masterHosts = [...masterHosts, ...transformedMasterHosts];
+      setInferredMasterHosts(masterHosts);
+    }
+    for (const slaveComponent of slaveComponents) {
+      const hostsWithSlaveComponent = filter(flattenedHostRoles, [
+        "component_name",
+        slaveComponent,
+      ]);
+
+      const transformedSlaveHosts = map(
+        hostsWithSlaveComponent,
+        function (slaveComponentHost: any) {
+          return {
+            component: slaveComponent,
+            hostName: slaveComponentHost.host_name,
+            isInstalled: true,
+            serviceId: get(slaveComponentHost, "service_name", ""),
+            display_name: get(slaveComponentHost, "display_name", ""),
+          };
+        }
+      );
+      slaveHosts = [...slaveHosts, ...transformedSlaveHosts];
+      setInferredSlaveHosts(masterHosts);
+    }
+    // const allStackServices = flatten(
+    //   map(serviceHostComponents, "host_components.[0].HostRoles")
+    // );
+    const allStackServices = getFlattenedcomponents();
+    const isHFDSInstalled = services.includes("HDFS");
+    const servicesToAdd: any = [];
+    const isHAEnabled =
+      isHFDSInstalled &&
+      !some(allStackServices, ["component_name", "SECONDARY_NAMENODE"]);
+    allStackServices.forEach((component: any) => {
+      // let component=componentHere;
+      // const matchingComponent=find(getFlattenedcomponents(), ["component_name", componentHere?.component_name]);
+      // if(matchingComponent){
+      //   component=matchingComponent
+      // }
+      if (component) {
+        const isMasterCreateOnConfig = mastersToCreate.includes(
+          get(component, "component_name", "") as never
+        );
+        //@ts-ignore
+        // const isMasterComponent=getFlattenedcomponents().find((c:any)=>c.component_name===component.component_name)?.is_master ;
+        if (
+          isShownOnAddServiceAssignMasterPage(
+            component.component_name,
+            component.is_master,
+            stack,
+            isHAEnabled
+          ) ||
+          mastersToShow.includes(component.component_name as never) ||
+          isMasterCreateOnConfig
+        ) {
+          stackMasterComponentsMap[get(component, "component_name", "")] =
+            component;
+        }
+      }
+    });
+    recommendations.blueprint_cluster_binding.host_groups.forEach(function (
+      group: any
+    ) {
+      hostGroupsMap[group.name] = group;
+    });
+    recommendations.blueprint.host_groups.forEach(function (host_group: any) {
+      let currentHosts = hostGroupsMap[host_group.name]
+        ? hostGroupsMap[host_group.name].hosts
+        : [];
+      currentHosts.forEach(function (host: any) {
+        host_group.components.forEach(function (component: any) {
+          component.component_name = component.name;
+          let willBeDisplayed = true;
+          let stackMasterComponent =
+            stackMasterComponentsMap[component.component_name];
+          if (stackMasterComponent) {
+            let isMasterCreateOnConfig = mastersToCreate.includes(
+              component.component_name as never
+            );
+            // If service is already installed and not being added as a new service then render on UI only those master components
+            // that have already installed hostComponents.
+            // NOTE: On upgrade there might be a prior installed service with non-installed newly introduced serviceComponent
+            if (
+              !servicesToAdd.includes(
+                get(stackMasterComponent, "serviceName")
+              ) &&
+              !isMasterCreateOnConfig
+            ) {
+              willBeDisplayed = some(masterHosts, [
+                "component",
+                component.component_name,
+              ]);
+            }
+
+            if (willBeDisplayed) {
+              let savedComponents = filter(masterHosts, [
+                "component",
+                component.component_name,
+              ]);
+              const multipleComponents = map(
+                filter(allStackServices, [
+                  "isMasterWithMultipleInstances",
+                  true,
+                ]),
+                "component_name"
+              );
+              if (
+                multipleComponents.includes(
+                  component.component_name as never
+                ) &&
+                savedComponents.length > 0
+              ) {
+                if (!multipleComponentHasBeenAdded[component.component_name]) {
+                  multipleComponentHasBeenAdded[component.component_name] =
+                    true;
+
+                  savedComponents.forEach(function (saved) {
+                    resultComponents.push(
+                      createComponentInstallationObject(
+                        stackMasterComponent,
+                        host.fqdn.toLowerCase(),
+                        saved
+                      )
+                    );
+                  });
+                }
+              } else {
+                var savedComponent = find(masterHosts, [
+                  "component",
+                  component.name,
+                ]);
+                resultComponents.push(
+                  createComponentInstallationObject(
+                    stackMasterComponent,
+                    host.fqdn.toLowerCase(),
+                    savedComponent
+                  )
+                );
+              }
+            }
+          }
+        });
+      });
+    });
+
+    return resultComponents;
+  }
+  function formatRecommendComponents(components: any) {
+    const res: any = [];
+    if (!components) return [];
+    components.forEach(function (component: any) {
+      var componentName = get(component, "component_name", "");
+      if (get(component, "hosts.length")) {
+        get(component, "hosts").forEach(function (hostName: string) {
+          res.push({
+            componentName: componentName,
+            hostName: hostName,
+          });
+        });
+      }
+    });
+    return res;
+  }
+  function getComponentsBlueprint(components: any) {
+    const uniqueHosts = uniq([
+      ...map(components, "hostName"),
+      ...map(hosts, "Hosts.host_name"),
+    ]);
+    const mappedComponents = groupPropertyValues(components, "hostName");
+    const res = {
+      blueprint: { host_groups: [] },
+      blueprint_cluster_binding: { host_groups: [] },
+    };
+    uniqueHosts.forEach(function (host, i) {
+      var group_name = "host-group-" + (i + 1);
+
+      res.blueprint.host_groups.push({
+        name: group_name,
+        components: mappedComponents[host]
+          ? mappedComponents[host].map(function (c: any) {
+              return { name: get(c, "componentName") };
+            })
+          : [],
+      } as never);
+
+      res.blueprint_cluster_binding.host_groups.push({
+        name: group_name,
+        hosts: [{ fqdn: host }],
+      } as never);
+    });
+    return res;
+  }
+  function getRecommendationRequestData(opts: any) {
+    return {
+      recommend: "host_groups",
+      hosts: opts.hosts,
+      services,
+      recommendations:
+        opts.blueprint || getComponentsBlueprint(opts.components),
+    };
+  }
+  async function getRecommendedHosts() {
+    const payloadObject = {
+      services: [],
+      hosts: map(hosts, "Hosts.host_name"),
+      components: [],
+      blueprint: null,
+    };
+    payloadObject.components = formatRecommendComponents(serviceHostComponents);
+    const payload = getRecommendationRequestData(payloadObject);
+    try {
+      const data = await AssignMastersApi.postRecommendations(
+        payload,
+        stack,
+        versionNum
+      );
+      // const recommendationsServer: any = get(
+      //   data,
+      //   "resources[0].recommendations",
+      //   []
+      // );
+      const payloadWithComponentsObject = {
+        services: [],
+        hosts: map(hosts, "Hosts.host_name"),
+        components: [],
+        blueprint: get(data, "resources[0].recommendations.blueprint", []),
+      };
+      const payloadWithComponents = getRecommendationRequestData(
+        payloadWithComponentsObject
+      );
+      const dataWithComponents = await AssignMastersApi.postRecommendations(
+        payloadWithComponents,
+        stack,
+        versionNum
+      );
+      const recommendationsServerWithComponents: any = get(
+        dataWithComponents,
+        "resources[0].recommendations",
+        []
+      );
+      setRecommendations(recommendationsServerWithComponents);
+      const recommendedHostsForComponent: any = {};
+      const hostsForHostGroup: any = {};
+      recommendationsServerWithComponents.blueprint_cluster_binding.host_groups.forEach(
+        function (hostGroup: any) {
+          hostsForHostGroup[hostGroup.name] = map(hostGroup.hosts, "fqdn");
+        }
+      );
+
+      recommendationsServerWithComponents.blueprint.host_groups.forEach(
+        function (hostGroup: any) {
+          var components = map(hostGroup.components, "name");
+          components.forEach(function (componentName: string) {
+            var hostList = recommendedHostsForComponent[componentName] || [];
+            var hostNames = hostsForHostGroup[hostGroup.name] || [];
+            hostList = [...hostList, ...hostNames];
+            recommendedHostsForComponent[componentName] = hostList;
+          });
+        }
+      );
+      setRecommendedHostsForComponents(recommendedHostsForComponent);
+    } catch (err) {
+      console.error("Could not load Recommendations");
+    }
+  }
+  async function fetchHosts() {
+    try {
+      const allHosts = await HostsApi.getHostComponentsDetails(
+        clusterName,
+        "fields=Hosts/cpu_count,Hosts/disk_info,Hosts/total_mem,Hosts/maintenance_state&minimal_response=true"
+      );
+      allHosts?.items.forEach((host: any) => {
+        host.host_info = {
+          cpu_count: host.Hosts.cpu_count,
+          disk_info: host.Hosts.disk_info,
+          total_mem: host.Hosts.total_mem,
+        };
+      });
+      setHosts(allHosts?.items);
+    } catch (err) {
+      console.error("Could Not Load Hosts");
+    }
+  }
+
+  function getFlattenedcomponents() {
+    return flatten(
+      map(
+        flatten(map(serviceComponents, "components")),
+        "StackServiceComponents"
+      )
+    );
+  }
+
+  function getMaxNumberOfMasters(componentName: string) {
+    const maxByCardinality = maxToInstall(
+      find(getFlattenedcomponents(), ["component_name", componentName])!
+    );
+    const hostsNumber = hosts.length;
+    return Math.min(maxByCardinality, hostsNumber);
+  }
+
+  function updateComponent(componentName: string) {
+    const selectedServicesMastersCopy = cloneDeep(
+      selectedServicesMastersRef.current
+    );
+    const component: any = filter(selectedServicesMastersCopy, [
+      "component_name",
+      componentName,
+    ])?.at(-1);
+    if (!component) {
+      return;
+    }
+
+    // PRIMARY RULE: In move/reassign scenarios, NEVER show add/remove controls
+    if (mastersToMove.length > 0) {
+      set(component, "showAddControl", false);
+      set(component, "showRemoveControl", false);
+      setSelectedServicesMasters(selectedServicesMastersCopy);
+      setServicesMasters(selectedServicesMastersCopy);
+      return;
+    }
+
+    // Get component stack service installation status
+    const stackComponent =
+      find(getFlattenedcomponents(), ["component_name", componentName]) || {};
+    const isServiceInstalled =
+      servicesData[get(stackComponent, "service_name", "")]?.installed;
+
+    // Show control if service is not installed or component is addable in HA
+    let showControl =
+      !isServiceInstalled ||
+      mastersAddableInHA.includes(componentName as never);
+    if (showControl) {
+      let mastersLength = filter(selectedServicesMastersRef.current, [
+        "component_name",
+        componentName,
+      ]).length;
+      if (mastersLength < getMaxNumberOfMasters(componentName)) {
+        set(component, "showAddControl", true);
+      } else {
+        if (component.isInstalled) {
+          set(component, "showRemoveControl", false);
+        } else {
+          set(component, "showRemoveControl", mastersLength != 1);
+        }
+      }
+    }
+    setSelectedServicesMasters(selectedServicesMastersCopy);
+    setServicesMasters(selectedServicesMastersCopy);
+    const addableMastersCopy = cloneDeep(addableMasters);
+    const currentComponentInAddableMasters = filter(
+      addableMastersCopy,
+      function (addableMaster: any) {
+        return addableMaster.component_name === componentName;
+      }
+    );
+    forEach(currentComponentInAddableMasters, function (addableMaster: any) {
+      const matchingComponentFromServiceCopy = find(
+        selectedServicesMastersCopy,
+        function (serviceMaster: any) {
+          return (
+            serviceMaster.component_name === addableMaster.component_name &&
+            serviceMaster.selectedHost === addableMaster.selectedHost
+          );
+        }
+      );
+      if (matchingComponentFromServiceCopy) {
+        merge(addableMaster, matchingComponentFromServiceCopy);
+      }
+    });
+    setAddableMasters(addableMastersCopy);
+    selectedServicesMastersRef.current = selectedServicesMastersCopy;
+    servicesMastersRef.current = selectedServicesMastersCopy;
+  }
+
+  function thereIsNoMasters() {
+    return !filter(selectedServicesMasters, ["isInstalled", false]).length;
+  }
+
+  async function loadStepCallback(components: any) {
+    const allComponents = flatten(
+      map(
+        flatten(map(serviceComponents, "components")),
+        "StackServiceComponents"
+      )
+    );
+    renderComponents(components);
+    const addableMasterInstallerWizard = (function () {
+      return map(
+        filter(allComponents, (component: any) => {
+          return isMasterAddableInstallerWizard(component);
+        }),
+        "component_name"
+      );
+    })();
+    const addableComponents = uniq([
+      ...addableMasterInstallerWizard,
+      ...mastersAddableInHA,
+    ]);
+    addableComponents.forEach((componentName: any) => {
+      updateComponent(componentName);
+    });
+
+    // Special handling for JOURNALNODE in HA mode (matching Ember implementation)
+    // In Ember, JOURNALNODE is handled by the showHideJournalNodesAddRemoveControl function
+    // even when it's not in mastersAddableInHA
+    if (mastersToShow.includes("JOURNALNODE")) {
+      updateComponent("JOURNALNODE");
+    }
+
+    if (thereIsNoMasters() && !mastersToCreate.length) {
+      //Enable Next
+    }
+  }
+
+  useEffect(() => {
+    fetchHosts();
+  }, []);
+
+  useEffect(() => {
+    if (serviceHostComponents.length && hosts.length) {
+      getRecommendedHosts();
+    }
+  }, [serviceHostComponents.length, hosts.length]);
+
+  useEffect(() => {
+    if (servicesMasters.length && !initiallyLoaded.current) {
+      initiallyLoaded.current = true;
+      servicesMastersToShow();
+    }
+  }, [servicesMasters.length]);
+
+  useEffect(() => {
+    if (addableMasters.length) {
+      masterHostMapping();
+    }
+  }, [addableMasters, servicesMasters]);
+
+  useEffect(() => {
+    if (!isEmpty(recommededHostsForComponents) && !isEmpty(recommendations)) {
+      loadStepCallback(createComponentInstallationObjects());
+    }
+  }, [!isEmpty(recommededHostsForComponents), !isEmpty(recommendations)]);
+
+  if (
+    !hosts.length ||
+    !serviceHostComponents.length ||
+    !masterHostsMapping.length
+  ) {
+    return <Spinner />;
+  }
+
+  const hostsOptions = hosts.map((host: any) => ({
+    label: host.Hosts.host_name,
+    value: host.Hosts.host_name,
+  }));
+
+  function changeHostNameForMaster(
+    componentIndex: number,
+    selectedHost: { label: string; value: string },
+    isMoving = false,
+    serviceComponentId?: string
+  ) {
+    const addableMastersCopy = cloneDeep(addableMasters);
+    if (isMoving) {
+      addableMastersCopy[componentIndex].movedHost = selectedHost.value;
+      addableMastersCopy[componentIndex].isMoving=true;
+    } else {
+      addableMastersCopy[componentIndex].selectedHost = selectedHost.value;
+      addableMastersCopy[componentIndex].hostName = selectedHost.value;
+    }
+    //change inferred masters as well
+    const inferrredCopy = cloneDeep(inferredMasterComponents);
+    const inferredComponent = find(inferrredCopy, function (comp) {
+      return (
+        comp.component_name ===
+          addableMastersCopy[componentIndex].component_name &&
+        comp.serviceComponentId === serviceComponentId &&
+        comp.isInstalled === false
+      );
+    });
+    if (isMoving) {
+      inferredComponent.movedHost = selectedHost.value;
+      inferredComponent.isMoving=true;
+    } else {
+      inferredComponent.selectedHost = selectedHost.value;
+      inferredComponent.hostName = selectedHost.value;
+    }
+    setInferredMasterComponents(inferrredCopy);
+    setSelectedServicesMasters(inferrredCopy);
+    setAddableMasters(addableMastersCopy);
+  }
+
+  function getHostOptionsFor(componentIndex: number) {
+    const selectedMaster = addableMasters[componentIndex];
+    const allMasters = cloneDeep(addableMasters);
+    const matchingMasters = allMasters.filter(
+      (master: any) => master.component_name === selectedMaster.component_name
+    );
+
+    // For reassign scenarios, we need to consider both selectedHost and movedHost
+    // to prevent duplicate host assignments
+    const usedHosts: string[] = [];
+    matchingMasters.forEach((master: any, index: number) => {
+      // Skip the current component being edited to allow it to select any host
+      if (index === componentIndex) {
+        return;
+      }
+      
+      // For other components of the same type, add their hosts to exclusion list
+      // Add the current selected host
+      if (master.selectedHost) {
+        usedHosts.push(master.selectedHost);
+      }
+      // For moving components, also add the moved host if it exists
+      if (master.movedHost) {
+        usedHosts.push(master.movedHost);
+      }
+    });
+
+    // Remove duplicates
+    const uniqueUsedHosts = uniq(usedHosts);
+
+    // For move scenarios, always allow the original host (selectedHost) to be available
+    // so users can revert back to the current host
+    const availableHosts = reject(hostsOptions, (hostOption: any) =>
+      uniqueUsedHosts.includes(hostOption.value)
+    );
+    
+    return availableHosts;
+  }
+  function addComponent(componentName: string) {
+    const maxNumMasters = getMaxNumberOfMasters(componentName);
+    const currentMasters = sortBy(
+      filter(addableMasters, ["component_name", componentName])
+    );
+    let newMaster = null;
+    let masterHosts = null;
+    let suggestedHost = null;
+    let i = 0;
+    let lastMaster = null;
+    if (!currentMasters.length) {
+      return false;
+    }
+    const servicesMastersCopy = cloneDeep(servicesMastersRef.current);
+    const selectedServicesMastersCopy = cloneDeep(
+      selectedServicesMastersRef.current
+    );
+    if (currentMasters.length < maxNumMasters) {
+      set(currentMasters.at(-1), "showAddControl", false);
+      // set(currentMasters.at(-1), "showRemoveControl", true);
+      newMaster = {};
+      lastMaster = currentMasters.at(-1);
+      set(newMaster, "display_name", get(lastMaster, "display_name", ""));
+      set(newMaster, "component_name", get(lastMaster, "component_name", ""));
+      set(newMaster, "component", get(lastMaster, "component_name", ""));
+      set(newMaster, "selectedHost", get(lastMaster, "selectedHost", ""));
+      set(newMaster, "hostName", get(lastMaster, "selectedHost", ""));
+      set(newMaster, "serviceId", get(lastMaster, "serviceId", ""));
+      set(newMaster, "isInstalled", false);
+      set(
+        newMaster,
+        "showAdditionalPrefix",
+        showAdditionalPrefix.includes(componentName)
+      );
+      if (currentMasters.length === maxNumMasters - 1) {
+        set(newMaster, "showAddControl", false);
+      } else {
+        set(newMaster, "showAddControl", true);
+      }
+      set(newMaster, "showRemoveControl", true);
+      masterHosts = uniq(map(currentMasters, "selectedHost"));
+      for (i = 0; i < hosts.length; i++) {
+        if (!masterHosts.includes(get(hosts[i], "Hosts.host_name"))) {
+          suggestedHost = get(hosts[i], "Hosts.host_name");
+          break;
+        }
+      }
+      set(newMaster, "selectedHost", suggestedHost);
+      set(newMaster, "hostName", suggestedHost);
+      if (!get(currentMasters?.at(-1), "serviceComponentId", undefined)) {
+        set(currentMasters?.at(-1), "serviceComponentId", 0);
+      }
+      set(
+        newMaster,
+        "serviceComponentId",
+        get(currentMasters?.at(-1), "serviceComponentId") + 1
+      );
+      // Add to all the necessary arrays
+      servicesMastersCopy.push(newMaster);
+      selectedServicesMastersCopy.push(newMaster);
+      currentMasters.push(newMaster);
+
+      // Update all state arrays with the new component
+      const addableMastersCopy = cloneDeep(addableMasters);
+      const otherMasters = addableMastersCopy.filter(
+        (m: any) => m.component_name !== componentName
+      );
+      const updatedAddableMasters = [...otherMasters, ...currentMasters];
+
+      // Update all refs and state
+      servicesMastersRef.current = servicesMastersCopy;
+      selectedServicesMastersRef.current = selectedServicesMastersCopy;
+
+      setSelectedServicesMasters(selectedServicesMastersCopy);
+      setServicesMasters(servicesMastersCopy);
+      setAddableMasters(updatedAddableMasters);
+      setInferredMasterComponents([...inferredMasterComponents, newMaster]);
... 21577 lines suppressed ...


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