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

arshad 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 bd31093e81 AMBARI-26580: Ambari Web React: Component actions for 
masters/slaves-Delete (#4108)
bd31093e81 is described below

commit bd31093e81609b5381fa6b69330b0145357aa13c
Author: Sandeep  Kumar <[email protected]>
AuthorDate: Wed Feb 4 11:05:41 2026 +0530

    AMBARI-26580: Ambari Web React: Component actions for masters/slaves-Delete 
(#4108)
---
 ambari-web/latest/src/Utils/Utility.ts             |    2 +-
 .../latest/src/hooks/useComponentAddDelete.tsx     | 1068 ++++++++++++++++++++
 .../latest/src/screens/Hosts/HostSummary.tsx       |   34 +-
 ambari-web/latest/src/screens/Hosts/actions.tsx    |   24 +
 ambari-web/latest/src/screens/Hosts/utils.tsx      |   52 +-
 5 files changed, 1176 insertions(+), 4 deletions(-)

diff --git a/ambari-web/latest/src/Utils/Utility.ts 
b/ambari-web/latest/src/Utils/Utility.ts
index 5b06a23455..3aabd48d35 100644
--- a/ambari-web/latest/src/Utils/Utility.ts
+++ b/ambari-web/latest/src/Utils/Utility.ts
@@ -69,7 +69,7 @@ const command: any = {
   "Included:": "Recommission:",
 };
 
-const serviceMap: any = {
+export const serviceMap: any = {
   HDFS: "HDFS",
   YARN: "YARN",
   MAPREDUCE2: "MapReduce2",
diff --git a/ambari-web/latest/src/hooks/useComponentAddDelete.tsx 
b/ambari-web/latest/src/hooks/useComponentAddDelete.tsx
new file mode 100644
index 0000000000..e73057d427
--- /dev/null
+++ b/ambari-web/latest/src/hooks/useComponentAddDelete.tsx
@@ -0,0 +1,1068 @@
+/**
+ * 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 { get, set, compact, map, flatten, isArray, has } from "lodash";
+import { useState, useRef, useContext, useEffect } from "react";
+import { t } from "i18next";
+import { IHost } from "../models/host";
+import { AppContext } from "../store/context";
+import { IHostComponent } from "../models/hostComponent";
+import modalManager from "../store/ModalManager";
+import { serviceMap } from "../Utils/Utility";
+import { HostsApi } from "../api/hostsApi";
+import { getComponentDisplayName, getServiceByConfigTypeMap, 
zooKeeperRelatedServices } from "../screens/Hosts/utils";
+import RecommendationModal from "../components/RecommendationModal";
+// import AddHiveComponentsInitializer from 
"../../../Initializers/AddHiveComponentsInitializer";
+// import AddZooKeeperComponentsInitializer from 
"../../../Initializers/AddZooKeeperComponentsInitializer";
+// import RecommendationModal from "../../../components/RecommendationModal";
+
+function useComponentAddDelete(
+  clusterComponents: any,
+  stackServices: any,
+  getConfigByName: Function,
+  setAllHostModels?: (
+    data: IHost[] | ((prevModels: IHost[]) => IHost[])
+  ) => void
+) {
+  const { clusterName, services } = useContext(AppContext);
+  // const { allServiceModels } = useContext(ServiceContext);
+  // const isNameNodeHAEnabled =
+  //   allServiceModels["hdfs"]?.isNameNodeHaEnabled || false;
+  const [configs, setConfigs] = useState({});
+  // const [isReconfigureRequired, setIsReconfigureRequired] = useState(false);
+  const isReconfigureRequired = useRef(false);
+
+  const [isConfigsLoadingInProgress, setIsConfigsLoadingInProgress] =
+    useState(false);
+  //@ts-ignore
+  const [allPropertiesToChangeState, setAllPropertiesToChangeState] = useState(
+    []
+  );
+
+  const [recommendedPropertiesToChange, setRecommendedPropertiesToChange] =
+    useState<any>([]);
+  const recommendedPropertiesToChangeRef = useRef<any>(
+    recommendedPropertiesToChange
+  );
+  const componentHere = useRef<IHostComponent | null>(null);
+  const allPropertiesToChange: any = useRef([]);
+  const requiredPropertiesToChange: any = useRef([]);
+  const groupedPropertiesToChange: any = useRef([]);
+  const _deletedHostComponentError = useRef<string>("");
+  const componentProperties = useRef([]);
+
+  useEffect(() => {
+    setAllPropertiesToChangeState(allPropertiesToChange.current);
+  }, [allPropertiesToChange.current]);
+
+  const deleteAndReconfigureComponent = async (
+    componentsMapItem: any,
+    component: IHostComponent
+  ) => {
+    componentHere.current = component;
+    if (componentsMapItem.deletePropertyName) {
+      set(
+        componentProperties.current,
+        componentsMapItem.deletePropertyName,
+        true
+      );
+    }
+    await loadComponentRelatedConfigs(
+      componentsMapItem.configTagsCallbackName,
+      componentsMapItem.configsCallbackName
+    );
+    modalManager.show(
+      <RecommendationModal
+        isOpen={true}
+        onClose={() => {
+          modalManager.hide();
+        }}
+        componentDisplayName={getComponentDisplayName(component)}
+        add={false}
+        
recommendedPropertiesToChange={recommendedPropertiesToChangeRef.current}
+        selectRecommendedProperties={(newProperties: any) => {
+          recommendedPropertiesToChangeRef.current = newProperties;
+        }}
+        //@ts-ignore
+        setRecommendedPropertiesToChange={setRecommendedPropertiesToChange}
+        callback={(properties: any) => {
+          setRecommendedPropertiesToChange(properties);
+          _doDeleteHostComponent(component, () => {
+            applyConfigsCustomization();
+            putConfigsToServer(
+              groupedPropertiesToChange.current,
+              get(component, "componentName")
+            );
+            clearConfigsChanges();
+          });
+        }}
+      />
+    );
+  };
+
+  useEffect(() => {
+    recommendedPropertiesToChangeRef.current = recommendedPropertiesToChange;
+  }, [recommendedPropertiesToChange]);
+
+  const putConfigsToServer = async (
+    groups: any,
+    componentName: any
+  ): Promise<void> => {
+    const requests: Promise<any>[] = [];
+    if (isArray(groups)) {
+      groups = flatten(groups);
+    }
+    if (groups.length) {
+      groups.forEach((group: any) => {
+        const desiredConfigs = [];
+        const properties = group.properties;
+        for (let site in properties) {
+          if (!properties.hasOwnProperty(site) || !properties[site]) continue;
+          desiredConfigs.push({
+            type: site,
+            properties: properties[site],
+            properties_attributes: group.properties_attributes[site],
+            service_config_version_note: t(
+              "hosts.host.configs.save.note"
+            ).replace("{0}", componentName),
+          });
+        }
+        if (desiredConfigs.length > 0) {
+          const data = {
+            desired_config: desiredConfigs,
+            componentName: componentName,
+          };
+          requests.push(
+            HostsApi.commonServiceConfigurations(clusterName, data)
+          );
+        }
+      });
+    }
+    try {
+      await Promise.all(requests);
+    } catch (error) {
+      console.error("Error while saving configurations: ", error);
+    }
+  };
+
+  const applyConfigsCustomization = () => {
+    recommendedPropertiesToChangeRef.current.forEach((property: any) => {
+      const value = property.saveRecommended
+        ? property.recommendedValue
+        : property.initialValue;
+      const filename = property.propertyFileName;
+      if (isArray(groupedPropertiesToChange.current)) {
+        groupedPropertiesToChange.current = flatten(
+          groupedPropertiesToChange.current
+        );
+      }
+      if (groupedPropertiesToChange.current.length) {
+        var group = groupedPropertiesToChange.current.find(
+          (item: { properties: Record<string, any> }) => {
+            return item.properties && has(item.properties, filename);
+          }
+        );
+        if (group) {
+          if (!group.properties[filename]) {
+            group.properties[filename] = {};
+          }
+          group.properties[filename][property.propertyName] = value;
+        }
+      }
+    });
+  };
+
+  const _doDeleteHostComponent = async (
+    component: IHostComponent,
+    deleteComponentSuccessCallback?: Function,
+    callback?: Function
+  ) => {
+    const componentName = get(component, "componentName");
+    const hostName = get(component, "hostName");
+    const url = componentName
+      ? 
`/clusters/${clusterName}/hosts/${hostName}/host_components/${componentName}`
+      : `/clusters/${clusterName}/hosts/${hostName}`;
+
+    try {
+      await HostsApi.componentDelete(url);
+      if (setAllHostModels) {
+        setAllHostModels((prevModels: IHost[]) => {
+          return prevModels.map((host) => {
+            if (host.hostName === hostName) {
+              const updatedHost = Object.create(Object.getPrototypeOf(host));
+              Object.assign(updatedHost, {
+                ...host,
+                hostComponents: host.hostComponents.filter(
+                  (hostComponent) =>
+                    hostComponent.componentName !== componentName
+                ),
+              });
+              return updatedHost as IHost;
+            }
+            return host;
+          });
+        });
+      }
+      if (deleteComponentSuccessCallback) {
+        deleteComponentSuccessCallback(componentName, hostName);
+      }
+
+      if (callback) {
+        callback();
+      }
+      _deletedHostComponentError.current = "";
+    } catch (err) {
+      _deletedHostComponentError.current = JSON.stringify(err);
+    }
+  };
+
+  const loadZookeeperConfigs = async (data: any, _opt: any, params: any) => {
+    const urlParams = constructZookeeperConfigUrlParams(data).join("|");
+    if (urlParams.length > 0) {
+      const response = await HostsApi.reAssignLoadConfigs(
+        clusterName,
+        urlParams
+      );
+      params.callback(response);
+    }
+  };
+
+  const saveZkConfigs = (data: any) => {
+    let configs: any = {};
+    let attributes: any = {};
+    saveLoadedConfigs(data);
+    data.items.forEach((item: any) => {
+      configs[item.type] = item.properties;
+      attributes[item.type] = item.properties_attributes || {};
+    });
+    updateZkConfigs(configs);
+    var groups: any = [];
+    var serviceNames = map(services, "ServiceInfo.service_name");
+    var zookeeperRelatedServices = zooKeeperRelatedServices.slice(0);
+    // if (isNameNodeHAEnabled) {
+    //   zookeeperRelatedServices.push({
+    //     serviceName: "HDFS",
+    //     typesToLoad: ["core-site"],
+    //     typesToSave: ["core-site"],
+    //   });
+    // }
+    zookeeperRelatedServices.forEach((service: any) => {
+      if (serviceNames.includes(service.serviceName)) {
+        var group: any = {
+          properties: {},
+          properties_attributes: {},
+        };
+
+        service.typesToSave.forEach((type: string) => {
+          if (configs[type]) {
+            group.properties[type] = configs[type];
+            group.properties_attributes[type] = attributes[type];
+          }
+        });
+        groups.push(group);
+      }
+    });
+    setConfigsChanges(groups);
+  };
+
+  const loadRangerConfigs = async (data: any, _opt: any, params: any) => {
+    const urlParams = getUrlParamsForConfigsRequest(data, [
+      "core-site",
+      "hdfs-site",
+      "kms-env",
+      "kms-site",
+    ]);
+    const response = await HostsApi.adminGetAllConfigurations(
+      clusterName,
+      urlParams
+    );
+    params.callback(response);
+  };
+
+  const onLoadRangerConfigs = (data: any) => {
+    const hdfsProperties = [
+        {
+          type: "core-site",
+          name: "hadoop.security.key.provider.path",
+        },
+        {
+          type: "hdfs-site",
+          name: "dfs.encryption.key.provider.uri",
+        },
+      ],
+      kmsSiteProperties = [
+        {
+          name: "hadoop.kms.cache.enable",
+          notHaValue: "true",
+          haValue: "false",
+        },
+        {
+          name: "hadoop.kms.authentication.zk-dt-secret-manager.enable",
+          notHaValue: "false",
+          haValue: "true",
+        },
+        {
+          name: "hadoop.kms.cache.timeout.ms",
+          notHaValue: "600000",
+          haValue: "0",
+        },
+        {
+          name: "hadoop.kms.current.key.cache.timeout.ms",
+          notHaValue: "30000",
+          haValue: "0",
+        },
+        {
+          name: "hadoop.kms.authentication.signer.secret.provider",
+          notHaValue: "random",
+          haValue: "zookeeper",
+        },
+        {
+          name: 
"hadoop.kms.authentication.signer.secret.provider.zookeeper.auth.type",
+          notHaValue: "kerberos",
+          haValue: "none",
+        },
+        {
+          name: 
"hadoop.kms.authentication.signer.secret.provider.zookeeper.connection.string",
+          notHaValue: "#HOSTNAME#:#PORT#,...",
+          haValue: getZookeeperConnectionString(),
+        },
+      ],
+      rkmsHosts = getRangerKMSServerHosts(),
+      rkmsHostsStr = rkmsHosts.join(";"),
+      isHA = rkmsHosts.length > 1,
+      rkmsPort = data.items.find(
+        (item: { type: string; properties: Record<string, any> }) =>
+          item.type === "kms-env"
+      )?.properties["kms_port"],
+      newValue = "kms://http@" + rkmsHostsStr + ":" + rkmsPort + "/kms",
+      coreSiteConfigs = data.items.find(
+        (item: {
+          type: string;
+          properties: Record<string, any>;
+          properties_attributes?: Record<string, any>;
+        }) => item.type === "core-site"
+      ),
+      hdfsSiteConfigs = data.items.find(
+        (item: { type: string }) => item.type === "hdfs-site"
+      ),
+      kmsSiteConfigs = data.items.find(
+        (item: { type: string }) => item.type === "kms-site"
+      ),
+      groups = [
+        {
+          properties: {
+            "core-site": coreSiteConfigs.properties,
+            "hdfs-site": hdfsSiteConfigs.properties,
+          },
+          properties_attributes: {
+            "core-site": coreSiteConfigs.properties_attributes,
+            "hdfs-site": hdfsSiteConfigs.properties_attributes,
+          },
+        },
+        {
+          properties: {
+            "kms-site": kmsSiteConfigs.properties,
+          },
+          properties_attributes: {
+            "kms-site": kmsSiteConfigs.properties_attributes,
+          },
+        },
+      ],
+      propertiesToChange = allPropertiesToChange.current;
+
+    saveLoadedConfigs(data);
+    hdfsProperties.forEach((property) => {
+      const typeConfigs = data.items.find(
+          (item: { type: string; properties: Record<string, any> }) =>
+            item.type === property.type
+        )?.properties,
+        currentValue = typeConfigs[property.name],
+        pattern = new RegExp("^kms:\\/\\/http@(.+):" + rkmsPort + "\\/kms$"),
+        patternMatch = currentValue && currentValue.match(pattern),
+        currentHostsList =
+          patternMatch && patternMatch[1].split(";").sort().join(";");
+      if (currentHostsList !== rkmsHostsStr) {
+        typeConfigs[property.name] = newValue;
+        if (isReconfigureRequired.current) {
+          const propertyFileName = property.type,
+            propertyName = property.name,
+            service =
+              getServiceByConfigTypeMap(stackServices)[propertyFileName],
+            configObject = getConfigByName(propertyName, propertyFileName);
+          const displayName = configObject && configObject.displayName;
+
+          // Ensure service display name is populated - fallback to serviceMap 
if needed
+          let serviceDisplayName =
+            service && service.StackServices?.display_name;
+          if (!serviceDisplayName) {
+            const serviceNameMapping: Record<string, string> = {
+              "hive-site": "Hive",
+              "webhcat-site": "Hive",
+              "hive-env": "Hive",
+              "yarn-site": "YARN",
+              "hbase-site": "HBase",
+              "accumulo-site": "Accumulo",
+              "kafka-broker": "Kafka",
+              "application-properties": "Atlas",
+              "infra-solr-env": "Ambari Infra Solr",
+              "storm-site": "Storm",
+              "core-site": "HDFS",
+              "hdfs-site": "HDFS",
+              "kms-site": "Ranger KMS",
+              "kms-env": "Ranger KMS",
+              "zoo.cfg": "ZooKeeper",
+            };
+            serviceDisplayName =
+              serviceNameMapping[propertyFileName] || propertyFileName;
+          }
+
+          propertiesToChange.push({
+            propertyFileName,
+            propertyName,
+            propertyTitle: configObject && `Service Config: ${displayName}`,
+            propertyDescription: configObject && configObject.description,
+            serviceDisplayName: serviceDisplayName,
+            initialValue: currentValue,
+            recommendedValue: newValue,
+            saveRecommended: true,
+          });
+        }
+      }
+    });
+
+    kmsSiteProperties.forEach((property) => {
+      const currentValue = kmsSiteConfigs.properties[property.name];
+      const newValue = isHA ? property.haValue : property.notHaValue;
+      kmsSiteConfigs.properties[property.name] = newValue;
+
+      propertiesToChange.push({
+        propertyFileName: "kms-site",
+        propertyName: property.name,
+        serviceDisplayName: serviceMap["RANGER_KMS"],
+        initialValue: currentValue,
+        recommendedValue: newValue,
+        saveRecommended: true,
+      });
+    });
+
+    allPropertiesToChange.current = propertiesToChange;
+    setConfigsChanges(groups);
+  };
+
+  const setConfigsChanges = (groups: any) => {
+    groupedPropertiesToChange.current.push(groups);
+    if (allPropertiesToChange.current.length) {
+      setConfigsChangesForDisplay();
+    } else {
+      setIsConfigsLoadingInProgress(false);
+    }
+  };
+
+  const setConfigsChangesForDisplay = () => {
+    allPropertiesToChange.current.forEach((property: any) => {
+      const stackProperty = getConfigByName(
+        property.propertyName,
+        property.propertyFileName
+      );
+      if (
+        stackProperty &&
+        (!stackProperty.isEditable || !stackProperty.isReconfigurable)
+      ) {
+        requiredPropertiesToChange.current.push(property);
+      } else {
+        set(property, "saveRecommeded", true);
+        set(property, "saveRecommended", true);
+        recommendedPropertiesToChangeRef.current.push(property);
+        setRecommendedPropertiesToChange(
+          recommendedPropertiesToChangeRef.current
+        );
+      }
+    });
+    setIsConfigsLoadingInProgress(false);
+  };
+
+  const loadHiveConfigs = async (data: any, _opt: any, params: any) => {
+    const urlParams = getUrlParamsForConfigsRequest(data, [
+      "hive-site",
+      "webcat-site",
+      "hive-env",
+      "core-site",
+    ]);
+    const response = await HostsApi.adminGetAllConfigurations(
+      clusterName,
+      urlParams
+    );
+    return params.callback(response);
+  };
+
+  const onLoadHiveConfigs = (data: any, _opt: any, _params: any) => {
+    let port = "";
+    let configs: any = {};
+    let attributes: any = {};
+    let userSetup: any = {};
+    // let localDB: any = {
+      masterComponentHosts: getHiveHosts()
+    // };
+    let dependencies: any = {
+      hiveMetastorePort: "",
+    };
+    // let initializer = new AddHiveComponentsInitializer(); TODO
+    saveLoadedConfigs(data);
+    data.items.forEach((item: any) => {
+      configs[item.type] = item.properties;
+      attributes[item.type] = item.properties_attributes || {};
+    });
+
+    var propertiesToChange = allPropertiesToChange.current;
+
+    port = configs["hive-site"]["hive.metastore.uris"].match(/:[0-9]{2,4}/);
+    port = port ? port[0].slice(1) : "9083";
+    dependencies.hiveMetastorePort = port;
+    userSetup.hiveUser = configs["hive-env"]["hive_user"];
+    // @ts-ignore
+    initializer.setup(userSetup.hiveUser);
+
+    ["hive-site", "webhcat-site", "hive-env", "core-site"].forEach(
+      (fileName) => {
+        if (configs[fileName]) {
+          Object.keys(configs[fileName]).forEach((propertyName) => {
+            const currentValue = configs[fileName][propertyName];
+            const propertyDef = {
+              name: propertyName,
+              value: currentValue,
+              filename: fileName,
+            };
+            // TODO: Use initializer to get default value
+            // const configProperty = initializer.initialValue(
+            //   propertyDef,
+            //   localDB,
+            //   dependencies
+            // );
+            // initializer.updateSiteObj(configs[fileName], configProperty);
+            if (
+              isReconfigureRequired.current &&
+              currentValue !== configs[fileName][propertyName]
+            ) {
+              const service =
+                getServiceByConfigTypeMap(stackServices)[fileName];
+              const configObject = getConfigByName(propertyName, fileName);
+              const displayName = configObject && configObject.displayName;
+
+              // Ensure service display name is populated - fallback to 
serviceMap if needed
+              let serviceDisplayName =
+                service && service.StackServices?.display_name;
+              if (!serviceDisplayName) {
+                // Fallback logic for service name mapping
+                const serviceNameMapping: Record<string, string> = {
+                  "hive-site": "Hive",
+                  "webhcat-site": "Hive",
+                  "hive-env": "Hive",
+                  "yarn-site": "YARN",
+                  "hbase-site": "HBase",
+                  "accumulo-site": "Accumulo",
+                  "kafka-broker": "Kafka",
+                  "application-properties": "Atlas",
+                  "infra-solr-env": "Ambari Infra Solr",
+                  "storm-site": "Storm",
+                  "core-site": "HDFS",
+                  "zoo.cfg": "ZooKeeper",
+                };
+                serviceDisplayName = serviceNameMapping[fileName] || fileName;
+              }
+
+              propertiesToChange.push({
+                propertyFileName: fileName,
+                propertyName,
+                propertyTitle:
+                  configObject &&
+                  t("installer.controls.serviceConfigPopover.title")
+                    .replace("{0}", displayName)
+                    .replace(
+                      "{1}",
+                      displayName === propertyName ? "" : propertyName
+                    ),
+                propertyDescription: configObject && configObject.description,
+                serviceDisplayName: serviceDisplayName,
+                initialValue: currentValue,
+                recommendedValue: propertyDef.value,
+                saveRecommended: true,
+              });
+            }
+          });
+        }
+      }
+    );
+    // initializer.cleanup();
+    //@ts-ignore
+    const uniquePropertiesToChange = propertiesToChange.filter(
+      (property: any, index: any, self: any) => {
+        const uniqueKey = 
`${property.propertyFileName}-${property.propertyName}`;
+        return (
+          index ===
+          self.findIndex(
+            (p: any) => `${p.propertyFileName}-${p.propertyName}` === uniqueKey
+          )
+        );
+      }
+    );
+
+    allPropertiesToChange.current = uniquePropertiesToChange;
+
+    const newGroups = [
+      {
+        properties: {
+          "hive-site": configs["hive-site"],
+          "webhcat-site": configs["webhcat-site"],
+          "hive-env": configs["hive-env"],
+        },
+        properties_attributes: {
+          "hive-site": attributes["hive-site"],
+          "webhcat-site": attributes["webhcat-site"],
+          "hive-env": attributes["hive-env"],
+        },
+      },
+      {
+        properties: {
+          "core-site": configs["core-site"],
+        },
+        properties_attributes: {
+          "core-site": attributes["core-site"],
+        },
+      },
+    ];
+    // initializer.cleanup(); TODO
+    setConfigsChanges(newGroups);
+  };
+
+  const getZookeeperConnectionString = () => {
+    const zkHosts = get(clusterComponents, "items", [])
+      .filter((item: any) => {
+        return (
+          get(item, "ServiceComponentInfo.component_name") ===
+          "ZOOKEEPER_SERVER"
+        );
+      })
+      .flatMap((item: any) => get(item, "host_components", []))
+      .map((hostComponent: any) => {
+        return get(hostComponent, "HostRoles.host_name");
+      });
+    return zkHosts
+      .map((host: any) => {
+        return host + ":2181";
+      })
+      .join(",");
+  };
+
+  const functionMapping = {
+    loadZookeeperConfigs,
+    saveZkConfigs,
+    loadRangerConfigs,
+    onLoadRangerConfigs,
+    loadHiveConfigs,
+    onLoadHiveConfigs,
+  };
+
+  const loadComponentRelatedConfigs = async (
+    configTagsCallbackName: keyof typeof functionMapping,
+    configsCallbackName: keyof typeof functionMapping
+  ) => {
+    clearConfigsChanges();
+    setIsConfigsLoadingInProgress(true);
+    //setIsReconfigureRequired(true);
+    isReconfigureRequired.current = true;
+    const configTagsCallback =
+      functionMapping[configTagsCallbackName as keyof typeof functionMapping];
+    const configsCallback =
+      functionMapping[configsCallbackName as keyof typeof functionMapping];
+    await loadConfigs(configTagsCallback, configsCallback);
+  };
+
+  const loadConfigs = async (
+    configTagsCallback: Function,
+    configsCallback: Function
+  ) => {
+    try {
+      const params = {
+        callback: configsCallback,
+      };
+      if (
+        typeof configTagsCallback !== "function" ||
+        typeof configsCallback !== "function"
+      ) {
+        throw new Error(
+          "Invalid function references passed to loadComponentRelatedConfigs"
+        );
+      }
+      const response = await HostsApi.configTags(clusterName);
+      return await configTagsCallback(response, {}, params);
+    } catch (err) {
+      console.error("Error in loading configs: ", err);
+    }
+  };
+
+  const constructZookeeperConfigUrlParams = (data: any) => {
+    const urlParams: any = [];
+
+    let zookeeperRelatedServices = zooKeeperRelatedServices.slice(0);
+    // handle HA enabled case.
+    // if (isNameNodeHAEnabled) {
+    //   zookeeperRelatedServices.push({
+    //     serviceName: "HDFS",
+    //     typesToLoad: ["core-site"],
+    //     typesToSave: ["core-site"],
+    //   });
+    // }
+    zookeeperRelatedServices.forEach((service: any) => {
+      if (
+        services.some(
+          (svc: any) => svc.ServiceInfo?.service_name === service.serviceName
+        )
+      ) {
+        service.typesToLoad.forEach((type: any) => {
+          if (data.Clusters.desired_configs[type]) {
+            urlParams.push(
+              "(type=" +
+                type +
+                "&tag=" +
+                data.Clusters.desired_configs[type].tag +
+                ")"
+            );
+          }
+        });
+      }
+    });
+    return urlParams;
+  };
+
+  const saveLoadedConfigs = (data: any) => {
+    setConfigs({
+      items: data.items.map((item: any) => {
+        return {
+          type: item.type,
+          properties_attributes: item.properties_attributes,
+          properties: item.properties,
+        };
+      }),
+    });
+  };
+
+  const clearConfigsChanges = (shouldKeepLoadingConfigs: boolean = false) => {
+    var arrayNames = [
+      "allPropertiesToChange",
+      "recommendedPropertiesToChange",
+      "requiredPropertiesToChange",
+      "groupedPropertiesToChange",
+    ];
+    arrayNames.forEach((name: string) => {
+      if (name === "allPropertiesToChange") {
+        allPropertiesToChange.current = [];
+      } else if (name === "recommendedPropertiesToChange") {
+        setRecommendedPropertiesToChange([]);
+      } else if (name === "requiredPropertiesToChange") {
+        requiredPropertiesToChange.current = [];
+      } else if (name === "groupedPropertiesToChange") {
+        groupedPropertiesToChange.current = [];
+      }
+    });
+    // setIsReconfigureRequired(false);
+    isReconfigureRequired.current = false;
+    if (!shouldKeepLoadingConfigs) {
+      setConfigs({});
+    }
+  };
+
+  const getUrlParamsForConfigsRequest = (data: any, configTypes: string[]) => {
+    return compact(
+      configTypes.map((type) => {
+        const tag = get(data, `Clusters.desired_configs.${type}.tag`, null);
+        return tag ? `(type=${type}&tag=${tag})` : null;
+      })
+    ).join("|");
+  };
+
+  const getRangerKMSServerHosts = () => {
+    var rkmsHosts = get(clusterComponents, "items", [])
+      .filter((item: any) => {
+        return (
+          get(item, "ServiceComponentInfo.component_name") ===
+          "RANGER_KMS_SERVER"
+        );
+      })
+      .flatMap((item: any) => get(item, "host_components", []))
+      .map((hostComponent: any) => {
+        return get(hostComponent, "HostRoles.host_name");
+      });
+
+    const rangerKMSServerHost = get(
+      componentProperties.current,
+      "rangerKMSServerHost",
+      null
+    );
+
+    if (rangerKMSServerHost) {
+      rkmsHosts.push(rangerKMSServerHost);
+    }
+
+    if (
+      get(componentProperties.current, "fromDeleteHost", false) ||
+      get(componentProperties.current, "deleteRangerKMSServer", false)
+    ) {
+      rkmsHosts = rkmsHosts.filter(
+        (host: string) => host !== get(componentHere.current, "hostName")
+      );
+    }
+    return rkmsHosts.sort();
+  };
+
+  const getHiveHosts = () => {
+    var removePerformed =
+      get(componentProperties.current, "fromDeleteHost", false) ||
+      get(componentProperties.current, "deleteHiveMetaStore", false) ||
+      get(componentProperties.current, "deleteHiveServer", false) ||
+      get(componentProperties.current, "deleteWebHCatServer", false);
+    var hiveMasterComponents = [
+      "WEBHCAT_SERVER",
+      "HIVE_METASTORE",
+      "HIVE_SERVER",
+    ];
+    var masterComponentsMap = hiveMasterComponents
+      .map((componentName: string) => {
+        return bootstrapHostsMapping(componentName);
+      })
+      .reduce((p: any, c: any) => {
+        return p.concat(c);
+      });
+
+    if (removePerformed) {
+      set(componentProperties.current, "deleteHiveMetaStore", false);
+      set(componentProperties.current, "deleteHiveServer", false);
+      set(componentProperties.current, "deleteWebHCatServer", false);
+      set(componentProperties.current, "fromDeleteHost", false);
+      masterComponentsMap = masterComponentsMap.map((masterComponent) => {
+        masterComponent.isInstalled =
+          masterComponent.hostName !== get(componentHere.current, "hostName");
+        return masterComponent;
+      });
+    }
+
+    if (get(componentProperties.current, "hiveMetastoreHost", false)) {
+      masterComponentsMap.push({
+        component: "HIVE_METASTORE",
+        hostName: get(componentProperties.current, "hiveMetastoreHost", ""),
+        isInstalled: !removePerformed,
+      });
+      set(componentProperties.current, "hiveMetastoreHost", "");
+    }
+
+    if (get(componentProperties.current, "hiveServerHost", false)) {
+      masterComponentsMap.push({
+        component: "HIVE_SERVER",
+        hostName: get(componentProperties.current, "hiveServerHost", ""),
+        isInstalled: !removePerformed,
+      });
+      set(componentProperties.current, "hiveServerHost", "");
+    }
+
+    if (get(componentProperties.current, "webhcatServerHost", false)) {
+      masterComponentsMap.push({
+        component: "webhcatServerHost",
+        hostName: get(componentProperties.current, "webhcatServerHost", ""),
+        isInstalled: !removePerformed,
+      });
+      set(componentProperties.current, "webhcatServerHost", "");
+    }
+    return masterComponentsMap;
+  };
+
+  const bootstrapHostsMapping = (
+    componentName: string,
+    hostNames: string[] = []
+  ) => {
+    if (
+      hostNames === null ||
+      hostNames === undefined ||
+      hostNames.length === 0
+    ) {
+      hostNames = get(clusterComponents, "items", [])
+        .filter((item: any) => {
+          return (
+            get(item, "ServiceComponentInfo.component_name") === componentName
+          );
+        })
+        .flatMap((item: any) => get(item, "host_components", []))
+        .map((hostComponent: any) => {
+          return get(hostComponent, "HostRoles.host_name");
+        });
+    }
+    return hostNames.map((hostName: string) => {
+      return {
+        component: componentName,
+        hostName: hostName,
+        isInstalled: true,
+      };
+    });
+  };
+
+  const updateZkConfigs = (configs: any) => {
+    // const portValue = configs["zoo.cfg"]?.clientPort;
+    // const zkPort = typeof portValue === "undefined" ? "2181" : portValue;
+    // const infraSolrZnode =
+    //   configs["infra-solr-env"]?.infra_solr_znode || "/ambari-solr";
+
+    // const initializer = new AddZooKeeperComponentsInitializer(); TODO
+    //@ts-ignore
+    initializer.setup();
+    const hostComponentsTopology: any = {
+      masterComponentHosts: [],
+    };
+    const propertiesToChange = allPropertiesToChange.current;
+    const masterComponents = bootstrapHostsMapping("ZOOKEEPER_SERVER");
+
+    if (
+      get(componentProperties.current, "fromDeleteHost", false) ||
+      get(componentProperties.current, "fromDeleteZkServer", false)
+    ) {
+      set(componentProperties.current, "fromDeleteHost", false);
+      set(componentProperties.current, "fromDeleteZkServer", false);
+      const removedHost = masterComponents.find(
+        (host) => host.hostName === get(componentHere.current, "hostName")
+      );
+      if (removedHost) {
+        removedHost.isInstalled = false;
+      }
+    } else if (get(componentProperties.current, "addZooKeeperServer", false)) {
+      set(componentProperties.current, "addZooKeeperServer", false);
+      const changedSelectedHostName = get(
+        componentProperties.current,
+        "selectedHost",
+        ""
+      );
+      const componentHost = get(componentHere, "hostName", "");
+      const selectedHostName = changedSelectedHostName
+        ? changedSelectedHostName
+        : componentHost;
+      masterComponents.push({
+        component: "ZOOKEEPER_SERVER",
+        hostName: selectedHostName,
+        isInstalled: true,
+      });
+    }
+
+    // TODO
+    // const dependencies = {
+    //   zkClientPort: zkPort,
+    //   infraSolrZnode,
+    // };
+
+    hostComponentsTopology.masterComponentHosts = masterComponents;
+
+    Object.keys(configs).forEach((fileName) => {
+      const properties = configs[fileName];
+      Object.keys(properties).forEach((propertyName) => {
+        const currentValue = properties[propertyName];
+        const propertyDef = {
+          filename: fileName,
+          name: propertyName,
+          value: currentValue,
+        };
+        //TODO
+        // const configProperty = initializer.initialValue(
+        //   propertyDef,
+        //   hostComponentsTopology,
+        //   dependencies
+        // );
+
+        // initializer.updateSiteObj(configs[fileName], configProperty);
+
+        if (currentValue !== configs[fileName][propertyName]) {
+          const service = getServiceByConfigTypeMap(stackServices)[fileName];
+          const configObject = getConfigByName(propertyName, fileName);
+          const displayName = configObject && configObject.displayName;
+
+          // Ensure service display name is populated - fallback to serviceMap 
if needed
+          let serviceDisplayName =
+            service && service.StackServices?.display_name;
+          if (!serviceDisplayName) {
+            // Fallback logic for service name mapping
+            const serviceNameMapping: Record<string, string> = {
+              "hive-site": "Hive",
+              "webhcat-site": "Hive",
+              "hive-env": "Hive",
+              "yarn-site": "YARN",
+              "hbase-site": "HBase",
+              "accumulo-site": "Accumulo",
+              "kafka-broker": "Kafka",
+              "application-properties": "Atlas",
+              "infra-solr-env": "Ambari Infra Solr",
+              "storm-site": "Storm",
+              "core-site": "HDFS",
+              "zoo.cfg": "ZooKeeper",
+            };
+            serviceDisplayName = serviceNameMapping[fileName] || fileName;
+          }
+
+          propertiesToChange.push({
+            propertyFileName: fileName,
+            propertyName,
+            propertyTitle:
+              configObject &&
+              t("installer.controls.serviceConfigPopover.title")
+                .replace("{0}", displayName)
+                .replace(
+                  "{1}",
+                  displayName === propertyName ? "" : propertyName
+                ),
+            propertyDescription: configObject && configObject.description,
+            serviceDisplayName: serviceDisplayName,
+            initialValue: currentValue,
+            recommendedValue: propertyDef.value,
+            saveRecommended: true,
+          });
+        }
+      });
+    });
+
+    allPropertiesToChange.current = propertiesToChange;
+  };
+
+  return {
+    deleteAndReconfigureComponent,
+    _doDeleteHostComponent,
+    loadComponentRelatedConfigs,
+    saveLoadedConfigs,
+    configs,
+    setConfigs,
+    // setIsReconfigureRequired,
+    setIsConfigsLoadingInProgress,
+    isReconfigureRequired: isReconfigureRequired.current,
+    isConfigsLoadingInProgress,
+    allPropertiesToChange,
+    recommendedPropertiesToChange,
+    requiredPropertiesToChange,
+    groupedPropertiesToChange,
+    _deletedHostComponentError,
+    clearConfigsChanges,
+    loadConfigs,
+    getUrlParamsForConfigsRequest,
+    applyConfigsCustomization,
+    putConfigsToServer,
+    setRecommendedPropertiesToChange,
+  };
+}
+
+export default useComponentAddDelete;
diff --git a/ambari-web/latest/src/screens/Hosts/HostSummary.tsx 
b/ambari-web/latest/src/screens/Hosts/HostSummary.tsx
index a0a684078f..579d4ae518 100644
--- a/ambari-web/latest/src/screens/Hosts/HostSummary.tsx
+++ b/ambari-web/latest/src/screens/Hosts/HostSummary.tsx
@@ -88,7 +88,8 @@ import {
   executeCustomCommand,
   installClients,
   installComponent,
-  refreshComponentConfigs
+  refreshComponentConfigs,
+  deleteComponent,
 } from "./actions";
 import { AppContext } from "../../store/context";
 import IHost from "../../models/host";
@@ -107,6 +108,7 @@ import { hostMetricsOption } from "./constants";
 import usePolling from "../../hooks/usePolling";
 import classNames from "classnames";
 import { useAuth } from "../../hooks/useAuth";
+import useComponentAddDelete from "../../hooks/useComponentAddDelete";
 
 type HostSummaryProps = {
   allHostModels: IHost[];
@@ -135,6 +137,22 @@ export default function HostsSummary({
   //Note:- Below states should be part of the context
   const [allComponents, setAllComponents] = useState<IHostComponent[]>([]);
   const [addableComponents, setAddableComponents] = useState<any[]>([]);
+  // const { services: stackServices } = useStackServices(); //TODO will be 
added later.
+  // const { getConfigByName } =  useConfigs([], stackServices as any); // 
TODO will be added later.
+
+  const stackServices = "";
+  const getConfigByName = () => {};
+
+  // const serviceConfigMap = getServiceByConfigTypeMap(stackServices);
+  const {
+    deleteAndReconfigureComponent,
+    _doDeleteHostComponent,
+  } = useComponentAddDelete(
+    clusterComponents,
+    stackServices,
+    getConfigByName,
+    setAllHostModels
+  );
 
   const [summary, setSummary] = useState({
     Hostname: "",
@@ -828,7 +846,19 @@ export default function HostsSummary({
                   : ""
               }
               onClick={() => {
-                //TODO: Will be implemented in future PR
+                if (
+                  !isDeleteComponentDisabled(
+                    component,
+                    get(clusterComponents, "items", [])
+                  )
+                ) {
+                  const data = {
+                    deleteAndReconfigureComponent,
+                    _doDeleteHostComponent,
+                    navigate,
+                  };
+                  deleteComponent(component, data);
+                }
               }}
             >
               Delete
diff --git a/ambari-web/latest/src/screens/Hosts/actions.tsx 
b/ambari-web/latest/src/screens/Hosts/actions.tsx
index d61260d650..12048140d0 100644
--- a/ambari-web/latest/src/screens/Hosts/actions.tsx
+++ b/ambari-web/latest/src/screens/Hosts/actions.tsx
@@ -19,6 +19,7 @@
 import { capitalize, cloneDeep, get, set, uniq } from "lodash";
 import { HostsApi } from "../../api/hostsApi";
 import {
+  addDeleteComponentsMap,
   doDecommissionRegionServer,
   doRecommissionAndStart,
   getComponentDisplayName,
@@ -42,6 +43,7 @@ import ConfirmationModal from 
"../../components/ConfirmationModal";
 import { IHost } from "../../models/host";
 import { t } from "i18next";
 import { CompatibleComponent, ComponentDependency } from 
"./utils/ComponentDependency";
+import RecommendationModal from "../../components/RecommendationModal";
 
 export const sendComponentCommand = async (
   component: IHostComponent,
@@ -686,4 +688,26 @@ export const refreshComponentConfigs = async (component: 
IHostComponent) => {
   });
 
   await HostsApi.clusterRequests(clusterName, data);
+};
+export const deleteComponent = async (component: IHostComponent, data: any) => 
{
+  const componentName = get(component, "componentName");
+  const componentsMapItem = get(addDeleteComponentsMap, componentName);
+
+  if (componentsMapItem) {
+    data.deleteAndReconfigureComponent(componentsMapItem, component);
+  } else if (componentName === "JOURNALNODE") {
+    data.navigate("/main/services/highAvailability/JournalNode/manage/step1");
+  } else {
+    modalManager.show(
+      <RecommendationModal
+        isOpen={true}
+        onClose={() => {
+          modalManager.hide();
+        }}
+        componentDisplayName={getComponentDisplayName(component)}
+        add={false}
+        callback={() => data._doDeleteHostComponent(component)}
+      />
+    );
+  }
 };
\ No newline at end of file
diff --git a/ambari-web/latest/src/screens/Hosts/utils.tsx 
b/ambari-web/latest/src/screens/Hosts/utils.tsx
index 26a70dc26c..325d9feda4 100644
--- a/ambari-web/latest/src/screens/Hosts/utils.tsx
+++ b/ambari-web/latest/src/screens/Hosts/utils.tsx
@@ -226,6 +226,44 @@ const serviceSpecificParams = {
   SSM: "host_components/processes/HostComponentProcess",
 };
 
+export const zooKeeperRelatedServices = [
+  {
+    serviceName: "HIVE",
+    typesToLoad: ["hive-site", "webhcat-site"],
+    typesToSave: ["hive-site", "webhcat-site"],
+  },
+  {
+    serviceName: "YARN",
+    typesToLoad: ["yarn-site", "zoo.cfg"],
+    typesToSave: ["yarn-site"],
+  },
+  {
+    serviceName: "HBASE",
+    typesToLoad: ["hbase-site"],
+    typesToSave: ["hbase-site"],
+  },
+  {
+    serviceName: "ACCUMULO",
+    typesToLoad: ["accumulo-site"],
+    typesToSave: ["accumulo-site"],
+  },
+  {
+    serviceName: "KAFKA",
+    typesToLoad: ["kafka-broker"],
+    typesToSave: ["kafka-broker"],
+  },
+  {
+    serviceName: "ATLAS",
+    typesToLoad: ["application-properties", "infra-solr-env"],
+    typesToSave: ["application-properties"],
+  },
+  {
+    serviceName: "STORM",
+    typesToLoad: ["storm-site"],
+    typesToSave: ["storm-site"],
+  },
+];
+
 var requestsRunningStatus = {
   updateServiceMetric: false,
 };
@@ -1480,4 +1518,16 @@ const createServiceComponent = (
     }).ServiceComponentInfo.service_name;
     HostsApi.commonCreateComponent(clusterName, serviceName, payload);
   }
-};
\ No newline at end of file
+};
+
+export function getServiceByConfigTypeMap(stackServices: any) {
+  let ret: any = {};
+  stackServices?.forEach(function (s: any) {
+    Object.keys(get(s, "StackServices.config_types", {})).forEach(function (
+      ct
+    ) {
+      ret[ct] = s;
+    });
+  });
+  return ret;
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to