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

dhavalshah9131 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit f2dcff02a053c9d633770ae9ea08c7b702b591bb
Author: Dhaval.Rajpara <[email protected]>
AuthorDate: Tue Jun 27 16:04:39 2023 +0530

    RANGER-4263 -LookupResource give blank response in new react UI
---
 .../AuditEvent/AdminLogs/PolicyViewDetails.jsx     |  15 +-
 .../views/PolicyListing/AddUpdatePolicyForm.jsx    |   4 +-
 .../src/views/Resources/ResourceComp.jsx           | 158 ++-------------
 .../src/views/Resources/ResourceSelectComp.jsx     | 215 +++++++++++++++++++++
 4 files changed, 246 insertions(+), 146 deletions(-)

diff --git 
a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/PolicyViewDetails.jsx
 
b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/PolicyViewDetails.jsx
index e5c8bc399..d74f9a83e 100644
--- 
a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/PolicyViewDetails.jsx
+++ 
b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/PolicyViewDetails.jsx
@@ -143,7 +143,8 @@ export function PolicyViewDetails(props) {
     updateTime,
     createdBy,
     createTime,
-    validitySchedules
+    validitySchedules,
+    zoneName
   } = access;
 
   const getPolicyDetails = () => {
@@ -325,7 +326,7 @@ export function PolicyViewDetails(props) {
         {getPolicyResources(policyType, resources)}
         <tr>
           <td className="text-nowrap">Description</td>
-          <td>{description}</td>
+          <td>{!isEmpty(description) ? description : "--"}</td>
         </tr>
         <tr>
           <td className="text-nowrap">Audit Logging </td>
@@ -337,6 +338,16 @@ export function PolicyViewDetails(props) {
             </h6>
           </td>
         </tr>
+        {!isEmpty(zoneName) && (
+          <tr>
+            <td className="text-nowrap">Zone Name </td>
+            <td>
+              <h6 className="d-inline mr-1">
+                <Badge variant="dark">{zoneName}</Badge>
+              </h6>
+            </td>
+          </tr>
+        )}
       </>
     );
   };
diff --git 
a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx
 
b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx
index 065f19e31..cc34488ea 100644
--- 
a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx
+++ 
b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx
@@ -696,7 +696,9 @@ export default function AddUpdatePolicyForm(props) {
           isRecursive:
             defObj.recursiveSupported &&
             !(values[`isRecursiveSupport-${level}`] === false),
-          values: values[`value-${level}`]?.map(({ value }) => value)
+          values: isArray(values[`value-${level}`])
+            ? values[`value-${level}`]?.map(({ value }) => value)
+            : [values[`value-${level}`].value]
         };
       }
     }
diff --git 
a/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx
 
b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx
index ae46317c1..452f05ace 100644
--- 
a/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx
+++ 
b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx
@@ -17,17 +17,16 @@
  * under the License.
  */
 
-import React, { useEffect, useReducer, useState, useRef } from "react";
+import React, { useEffect, useState, useRef } from "react";
 import { Form as FormB, Row, Col } from "react-bootstrap";
 import { Field } from "react-final-form";
 import Select from "react-select";
 import BootstrapSwitchButton from "bootstrap-switch-button-react";
-import CreatableSelect from "react-select/creatable";
-import { debounce, filter, groupBy, some, sortBy } from "lodash";
+import { filter, groupBy, some, sortBy } from "lodash";
 import { toast } from "react-toastify";
 import { udfResourceWarning } from "../../utils/XAMessages";
-import { fetchApi } from "Utils/fetchAPI";
 import { RangerPolicyType } from "Utils/XAEnums";
+import ResourceSelectComp from "./ResourceSelectComp";
 
 const noneOptions = {
   label: "None",
@@ -44,8 +43,6 @@ export default function ResourceComp(props) {
     policyId
   } = props;
   const [rsrcState, setLoader] = useState({ loader: false, resourceKey: -1 });
-  const [options, setOptions] = useState([]);
-  const [isLoading, setIsLoading] = useState(false);
   const toastId = useRef(null);
 
   let resources = sortBy(serviceCompDetails.resources, "itemId");
@@ -73,52 +70,6 @@ export default function ResourceComp(props) {
   }
   grpResourcesKeys = grpResourcesKeys.sort();
 
-  const fetchResourceLookup = async (
-    inputValue,
-    resourceObj,
-    selectedValues
-  ) => {
-    let resourceName = resourceObj.name;
-    let data = {
-      resourceName,
-      resources: {
-        [resourceName]: selectedValues?.map?.(({ value }) => value) || []
-      }
-    };
-    if (inputValue) {
-      data["userInput"] = inputValue || "";
-    }
-
-    let op = [];
-    try {
-      if (resourceObj.lookupSupported) {
-        const resourceResp = await fetchApi({
-          url: `plugins/services/lookupResource/${serviceDetails.name}`,
-          method: "POST",
-          data
-        });
-        op =
-          resourceResp.data?.map?.((name) => ({
-            label: name,
-            value: name
-          })) || [];
-      }
-    } catch (error) {
-      toast.dismiss(toastId.current);
-      if (error?.response?.data?.msgDesc) {
-        toastId.current = toast.error(error.response.data.msgDesc);
-      } else {
-        toastId.current = toast.error(
-          "Resouce lookup failed for current resource"
-        );
-      }
-    }
-
-    setOptions(op);
-  };
-
-  const fetchDelayResourceLookup = debounce(fetchResourceLookup, 1000);
-
   const getResourceLabelOp = (levelKey, index) => {
     let op = grpResources[levelKey];
     if (index !== 0) {
@@ -150,10 +101,7 @@ export default function ResourceComp(props) {
     if (index !== 0) {
       levelOp = getResourceLabelOp(levelKey, index);
     }
-    if (
-      levelOp.length === 1 &&
-      !formValues[resourceKey].hasOwnProperty("parent")
-    ) {
+    if (levelOp.length === 1 && !formValues[resourceKey]?.parent?.length > 0) {
       renderLabel = true;
     } else {
       if (index !== 0) {
@@ -236,34 +184,6 @@ export default function ResourceComp(props) {
     }
   };
 
-  const required = (val, formVal) => {
-    if (!val || val.length == 0) {
-      return "Required";
-    }
-    if (formVal?.validationRegEx && val?.length > 0) {
-      var regex = new RegExp(formVal.validationRegEx);
-      if (formVal.validationRegEx == "^\\*$") {
-        if (regex.test(val[val.length - 1].value) == false)
-          return 'Only "*" value is allowed';
-      }
-      if (formVal.validationRegEx == "^[/*]$|^/.*?[^/]$") {
-        if (regex.test(val[val.length - 1].value) == false)
-          return "Relative Path start with slash and must not end with a 
slash";
-      }
-    }
-  };
-
-  const onLookupChange = (object, resourceObj, selectedValues, { action }) => {
-    switch (action) {
-      case "input-change":
-        if (object)
-          fetchDelayResourceLookup(object, resourceObj, selectedValues);
-        return;
-      default:
-        return;
-    }
-  };
-
   return grpResourcesKeys.map((levelKey, index) => {
     const resourceKey = `resourceName-${levelKey}`;
     if (index !== 0) {
@@ -284,10 +204,6 @@ export default function ResourceComp(props) {
       })
     };
 
-    const rcsValidation = (m) => {
-      return required(m, formValues[`resourceName-${levelKey}`]);
-    };
-
     return (
       <FormB.Group
         as={Row}
@@ -329,62 +245,18 @@ export default function ResourceComp(props) {
             }
           />
         </Col>
+
         {formValues[`resourceName-${levelKey}`] && (
-          <Col sm={5}>
-            <Field
-              key={formValues[`resourceName-${levelKey}`].name}
-              className="form-control"
-              name={`value-${levelKey}`}
-              validate={
-                formValues &&
-                formValues[`resourceName-${levelKey}`]?.mandatory &&
-                rcsValidation
-              }
-              render={({ input, meta }) => (
-                <>
-                  <CreatableSelect
-                    {...input}
-                    id={
-                      formValues &&
-                      formValues[`resourceName-${levelKey}`]?.mandatory &&
-                      meta.error &&
-                      meta.touched
-                        ? "isError"
-                        : `value-${levelKey}`
-                    }
-                    isMulti
-                    isDisabled={
-                      formValues[`resourceName-${levelKey}`].value ===
-                      noneOptions.value
-                    }
-                    options={options}
-                    onFocus={() => {
-                      fetchResourceLookup(
-                        "",
-                        formValues[`resourceName-${levelKey}`],
-                        input.value
-                      );
-                    }}
-                    onInputChange={(inputVal, action) => {
-                      onLookupChange(
-                        inputVal,
-                        formValues[`resourceName-${levelKey}`],
-                        input.value,
-                        action
-                      );
-                    }}
-                    isLoading={isLoading}
-                  />
-                  {formValues &&
-                    formValues[`resourceName-${levelKey}`]?.mandatory &&
-                    meta.touched &&
-                    meta.error && (
-                      <span className="invalid-field">{meta.error}</span>
-                    )}
-                </>
-              )}
-            />
-          </Col>
+          <>
+            <Col sm={5}>
+              <ResourceSelectComp
+                levelKey={levelKey}
+                formValues={formValues}
+                grpResourcesKeys={grpResourcesKeys}
+                serviceDetails={serviceDetails}
+              />
+            </Col>
+          </>
         )}
         {formValues[`resourceName-${levelKey}`] && (
           <Col sm={4}>
diff --git 
a/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceSelectComp.jsx
 
b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceSelectComp.jsx
new file mode 100644
index 000000000..1b8903c97
--- /dev/null
+++ 
b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceSelectComp.jsx
@@ -0,0 +1,215 @@
+/*
+ * 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 React, { useState, useRef } from "react";
+import { Field } from "react-final-form";
+import CreatableSelect from "react-select/creatable";
+import { debounce, isArray } from "lodash";
+import { toast } from "react-toastify";
+import { fetchApi } from "Utils/fetchAPI";
+
+const noneOptions = {
+  label: "None",
+  value: "none"
+};
+
+export default function ResourceSelectComp(props) {
+  const { formValues, grpResourcesKeys, levelKey, serviceDetails } = props;
+  const [options, setOptions] = useState([]);
+  const [isLoading, setIsLoading] = useState(false);
+  const toastId = useRef(null);
+
+  const fetchResourceLookup = async (
+    inputValue,
+    resourceObj,
+    selectedFormValues
+  ) => {
+    setIsLoading(true);
+    let resourceName = resourceObj.name;
+    let resourceDataLevel = grpResourcesKeys.slice(
+      0,
+      grpResourcesKeys.indexOf(resourceObj.level) + 1
+    );
+    let resourceData = {};
+    if (resourceDataLevel.length > 0) {
+      resourceDataLevel.map(function (m) {
+        resourceData[selectedFormValues[`resourceName-${m}`].name] = isArray(
+          selectedFormValues[`value-${m}`]
+        )
+          ? selectedFormValues[`value-${m}`]?.map?.(({ value }) => value) || []
+          : selectedFormValues[`value-${m}`] != undefined
+          ? [selectedFormValues[`value-${m}`].value]
+          : [];
+      });
+    }
+    let data = {
+      resourceName,
+      resources: resourceData,
+      userInput: inputValue || ""
+    };
+
+    let op = [];
+    try {
+      if (resourceObj.lookupSupported) {
+        const resourceResp = await fetchApi({
+          url: `plugins/services/lookupResource/${serviceDetails.name}`,
+          method: "POST",
+          data
+        });
+        op =
+          resourceResp.data?.map?.((name) => ({
+            label: name,
+            value: name
+          })) || [];
+      }
+    } catch (error) {
+      setIsLoading(false);
+      toast.dismiss(toastId.current);
+      if (error?.response?.data?.msgDesc) {
+        toastId.current = toast.error(error.response.data.msgDesc);
+      } else {
+        toastId.current = toast.error(
+          "Resouce lookup failed for current resource"
+        );
+      }
+    }
+    setOptions(op);
+    setIsLoading(false);
+  };
+
+  const fetchDelayResourceLookup = useRef(debounce(fetchResourceLookup, 1000));
+
+  const required = (val, formVal) => {
+    if (!val || val.length == 0) {
+      return "Required";
+    }
+    if (formVal?.validationRegEx && val?.length > 0) {
+      var regex = new RegExp(formVal.validationRegEx);
+      if (formVal.validationRegEx == "^\\*$") {
+        if (regex.test(val[val.length - 1].value) == false)
+          return 'Only "*" value is allowed';
+      }
+      if (formVal.validationRegEx == "^[/*]$|^/.*?[^/]$") {
+        if (regex.test(val[val.length - 1].value) == false)
+          return "Relative Path start with slash and must not end with a 
slash";
+      }
+    }
+  };
+
+  const onLookupChange = (
+    object,
+    resourceObj,
+    selectedFormValues,
+    { action }
+  ) => {
+    switch (action) {
+      case "input-change":
+        if (object != undefined) {
+          setIsLoading(true);
+          setOptions([]);
+          fetchDelayResourceLookup.current(
+            object,
+            resourceObj,
+            selectedFormValues
+          );
+        }
+        return;
+      default:
+        return;
+    }
+  };
+
+  const rcsValidation = (m) => {
+    return required(m, formValues[`resourceName-${levelKey}`]);
+  };
+
+  const supportMultipleVal = (rscVal) => {
+    if (rscVal?.uiHint) {
+      let singleVal = JSON.parse(rscVal.uiHint);
+      return singleVal.singleValue ? false : true;
+    } else {
+      return true;
+    }
+  };
+
+  const customFilterOptions = (option, rawInput) => {
+    const inputValue = rawInput.trim().toLowerCase();
+
+    if (!inputValue || inputValue == "*") {
+      return true; // Show all options when input is empty
+    }
+    return true;
+  };
+
+  return (
+    <Field
+      key={formValues[`resourceName-${levelKey}`].name}
+      className="form-control"
+      name={`value-${levelKey}`}
+      validate={
+        formValues &&
+        formValues[`resourceName-${levelKey}`]?.mandatory &&
+        rcsValidation
+      }
+      render={({ input, meta }) => (
+        <>
+          <CreatableSelect
+            {...input}
+            id={
+              formValues &&
+              formValues[`resourceName-${levelKey}`]?.mandatory &&
+              meta.error &&
+              meta.touched
+                ? "isError"
+                : `value-${levelKey}`
+            }
+            
isMulti={supportMultipleVal(formValues[`resourceName-${levelKey}`])}
+            isClearable
+            isDisabled={
+              formValues[`resourceName-${levelKey}`].value === 
noneOptions.value
+            }
+            options={options}
+            onFocus={(e) => {
+              setOptions([]);
+              fetchResourceLookup(
+                "",
+                formValues[`resourceName-${levelKey}`],
+                formValues
+              );
+            }}
+            onInputChange={(inputVal, action) => {
+              onLookupChange(
+                inputVal,
+                formValues[`resourceName-${levelKey}`],
+                formValues,
+                action
+              );
+            }}
+            filterOption={customFilterOptions}
+            isLoading={isLoading}
+          />
+          {formValues &&
+            formValues[`resourceName-${levelKey}`]?.mandatory &&
+            meta.touched &&
+            meta.error && <span className="invalid-field">{meta.error}</span>}
+        </>
+      )}
+    />
+  );
+}

Reply via email to