This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ranger.git
commit c9a08e68325a94ea34325b88e7f45290f0ee8bda Author: Brijesh Bhalala <brijeshbhalala2...@gmail.com> AuthorDate: Thu Oct 5 19:21:33 2023 +0530 RANGER-4424: UI updates to support security zones without any resource Signed-off-by: Madhan Neethiraj <mad...@apache.org> --- .../main/resources/META-INF/jpa_named_queries.xml | 2 +- .../webapp/react-webapp/src/images/no-service.svg | 4 + .../AuditEvent/AdminLogs/SecurityZonelogs.jsx | 530 ++++++++++++--------- .../src/views/AuditEvent/OperationAdminModal.jsx | 11 +- .../src/views/SecurityZone/SecurityZoneForm.jsx | 126 +++-- .../src/views/SecurityZone/ZoneDisplay.jsx | 158 +++--- .../src/views/SecurityZone/ZoneListing.jsx | 2 +- .../views/ServiceManager/ServiceDefinitions.jsx | 60 ++- 8 files changed, 495 insertions(+), 398 deletions(-) diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml index d3246c60c..33172ce85 100755 --- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml +++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml @@ -324,7 +324,7 @@ </named-query> <named-query name="XXTrxLog.findByTrxId"> - <query>SELECT obj FROM XXTrxLog obj WHERE obj.transactionId = :transactionId + <query>SELECT obj FROM XXTrxLog obj WHERE obj.transactionId = :transactionId order by obj.id </query> </named-query> diff --git a/security-admin/src/main/webapp/react-webapp/src/images/no-service.svg b/security-admin/src/main/webapp/react-webapp/src/images/no-service.svg new file mode 100644 index 000000000..a72198016 --- /dev/null +++ b/security-admin/src/main/webapp/react-webapp/src/images/no-service.svg @@ -0,0 +1,4 @@ +<svg width="415" height="419" viewBox="0 0 415 419" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M107.719 251.062C101.463 251.062 96.1439 248.871 91.7615 244.489C87.379 240.106 85.1878 234.787 85.1878 228.531V81.212C85.1878 74.956 87.5029 69.513 92.1329 64.8829C96.763 60.2528 102.206 57.9378 108.462 57.9378H179.15L204.9 83.6878H306.538C312.299 83.6878 317.267 85.5489 321.443 89.2711C325.619 92.9932 328.038 97.5695 328.698 103H197.002L171.252 77.25H108.462C107.306 77.25 106.357 77.6214 105.614 78.3643C104.871 79.1072 104.5 80.0564 104.5 81.212V227.788C104.5 228.696 104.727 2 [...] +<path d="M48.017 349.636V402H40.7557L14.1392 363.597H13.6534V402H5.75284V349.636H13.0653L39.7074 388.091H40.1932V349.636H48.017ZM75.4709 402.793C71.7891 402.793 68.576 401.949 65.8317 400.261C63.0874 398.574 60.9567 396.213 59.4396 393.179C57.9226 390.145 57.1641 386.599 57.1641 382.543C57.1641 378.469 57.9226 374.906 59.4396 371.855C60.9567 368.804 63.0874 366.435 65.8317 364.747C68.576 363.06 71.7891 362.216 75.4709 362.216C79.1527 362.216 82.3658 363.06 85.1101 364.747C87.8544 366.435 [...] +</svg> diff --git a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/SecurityZonelogs.jsx b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/SecurityZonelogs.jsx index c6ab380b7..a582cbb8b 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/SecurityZonelogs.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminLogs/SecurityZonelogs.jsx @@ -25,21 +25,57 @@ import { isEmpty } from "lodash"; export const SecurityZonelogs = ({ data, reportdata }) => { const { objectName, objectClassType, createDate, owner, action } = data; - - const updateZoneDetails = reportdata.filter( - (zone) => zone.action == "update" && zone.attributeName !== "Zone Services" - ); - - const updateZoneServices = reportdata.filter( - (zone) => zone.action == "update" && zone.attributeName == "Zone Services" - ); - const createZoneDetails = (newvalue) => { return !isEmpty(newvalue.replace(/[[\]]/g, "")) ? newvalue.replace(/[[\]]/g, "") : "--"; }; + const zoneServiceData = (reportdata, action, attributeName) => { + return reportdata.filter( + (zone) => zone.action == action && zone.attributeName == attributeName + ); + }; + const createZoneServices = zoneServiceData( + reportdata, + "create", + "Zone Services" + ); + + const deleteZoneServices = zoneServiceData( + reportdata, + "delete", + "Zone Services" + ); + const parseAndFilterData = (zones, zoneValues) => { + return zones.map( + (zone) => !isEmpty(zone[zoneValues]) && JSON.parse(zone[zoneValues]) + ); + }; + + const newZoneServiceData = parseAndFilterData(createZoneServices, "newValue"); + const oldZoneServiceData = parseAndFilterData( + deleteZoneServices, + "previousValue" + ); + const updateZoneDetails = reportdata.filter( + (zone) => zone.action == "update" && zone.attributeName != "Zone Services" + ); + + const updateZoneServices = zoneServiceData( + reportdata, + "update", + "Zone Services" + ); + + const updateZoneOldServices = parseAndFilterData( + updateZoneServices, + "previousValue" + ); + const updateZoneNewServices = parseAndFilterData( + updateZoneServices, + "newValue" + ); return ( <div> {/* CREATE */} @@ -83,31 +119,31 @@ export const SecurityZonelogs = ({ data, reportdata }) => { })} </Table> <br /> - <h5 className="bold wrap-header m-t-sm">Zone Service Details:</h5> - <Table className="table table-striped table-bordered w-75"> - <thead className="thead-light"> - <tr> - <th>Service Name</th> + {!isEmpty(Object.keys(newZoneServiceData[0] || {})) && ( + <> + <h5 className="bold wrap-header m-t-sm"> + Zone Service Details: + </h5> + <Table className="table table-striped table-bordered w-75"> + <thead className="thead-light"> + <tr> + <th>Service Name</th> - <th>Zone Service Resources</th> - </tr> - </thead> + <th>Zone Service Resources</th> + </tr> + </thead> - {reportdata - .filter((obj) => obj.attributeName == "Zone Services") - .map((key) => { - return ( - !isEmpty(key.newValue) && - Object.keys(JSON.parse(key.newValue)).map((c) => { - return ( - <tbody> - <tr> - <td className="table-warning align-middle"> - <strong> {c}</strong> - </td> - <td className="table-warning "> + {Object.entries(newZoneServiceData[0])?.map(([key]) => { + return ( + <tbody> + <tr> + <td className="table-warning align-middle"> + <strong> {key}</strong> + </td> + {!isEmpty(newZoneServiceData[0][key].resources) ? ( + <td className="table-warning"> {Object.values( - JSON.parse(key.newValue)[c].resources + newZoneServiceData[0][key].resources ).map((resource) => ( <div className="zone-resource"> {Object.keys(resource).map((policy) => { @@ -122,13 +158,16 @@ export const SecurityZonelogs = ({ data, reportdata }) => { </div> ))} </td> - </tr> - </tbody> - ); - }) - ); - })} - </Table> + ) : ( + <td className="text-center table-warning">--</td> + )} + </tr> + </tbody> + ); + })} + </Table> + </> + )} </div> )} @@ -136,188 +175,220 @@ export const SecurityZonelogs = ({ data, reportdata }) => { {action == "update" && objectClassType == ClassTypes.CLASS_TYPE_RANGER_SECURITY_ZONE.value && ( - <div> - <div className="row"> - <div className="col-md-6"> - <div className="font-weight-bolder">Name: {objectName}</div> - <div className="font-weight-bolder"> - Date: {dateFormat(createDate, "mm/dd/yyyy hh:MM:ss TT ")} - India Standard Time + <> + <div> + <div className="row"> + <div className="col-md-6"> + <div className="font-weight-bolder">Name: {objectName}</div> + <div className="font-weight-bolder"> + Date: {dateFormat(createDate, "mm/dd/yyyy hh:MM:ss TT ")} + India Standard Time + </div> + <div className="font-weight-bolder">Updated By: {owner}</div> + </div> + <div className="col-md-6 text-right"> + <div className="bg-success legend"></div> {" Added "} + <div className="bg-danger legend"></div> {" Deleted "} </div> - <div className="font-weight-bolder">Updated By: {owner}</div> - </div> - <div className="col-md-6 text-right"> - <div className="bg-success legend"></div> {" Added "} - <div className="bg-danger legend"></div> {" Deleted "} </div> - </div> - <br /> - {action == "update" && !isEmpty(updateZoneDetails) && ( - <> - <h5 className="bold wrap-header m-t-sm">Zone Details:</h5> + <br /> + {action == "update" && !isEmpty(updateZoneDetails) && ( + <> + <h5 className="bold wrap-header m-t-sm">Zone Details:</h5> - <Table className="table table-bordered table-striped w-auto"> - <thead className="thead-light"> - <tr> - <th>Fields</th> - <th>Old Value</th> - <th>New Value</th> - </tr> - </thead> - {updateZoneDetails.map((obj) => ( - <tbody> - <tr key={obj.id}> - <td className="table-warning text-nowrap"> - {obj.attributeName} - </td> + <Table className="table table-bordered table-striped w-auto"> + <thead className="thead-light"> + <tr> + <th>Fields</th> + <th>Old Value</th> + <th>New Value</th> + </tr> + </thead> + {updateZoneDetails.map((obj) => ( + <tbody> + <tr key={obj.id}> + <td className="table-warning text-nowrap"> + {!isEmpty(obj.attributeName) + ? obj.attributeName + : "--"} + </td> - <td className="table-warning text-nowrap"> - {!isEmpty(obj.previousValue.replace(/[[\]]/g, "")) ? ( - isEmpty(obj.newValue.replace(/[[\]]/g, "")) ? ( - <h6> - <Badge - className="d-inline mr-1" - variant="danger" - > - {obj.previousValue.replace(/[[\]]/g, "")} - </Badge> - </h6> - ) : ( + <td className="table-warning text-nowrap"> + {!isEmpty( obj.previousValue.replace(/[[\]]/g, "") - ) - ) : ( - "--" - )} - </td> - <td className="table-warning text-nowrap"> - {!isEmpty(obj.newValue.replace(/[[\]]/g, "")) ? ( - isEmpty(obj.previousValue.replace(/[[\]]/g, "")) ? ( - <h6> - <Badge - className="d-inline mr-1" - variant="success" - > - {obj.newValue.replace(/[[\]]/g, "")} - </Badge> - </h6> + ) ? ( + isEmpty(obj.newValue.replace(/[[\]]/g, "")) ? ( + <h6> + <Badge + className="d-inline mr-1" + variant="danger" + > + {obj.previousValue.replace(/[[\]]/g, "")} + </Badge> + </h6> + ) : ( + obj.previousValue.replace(/[[\]]/g, "") + ) ) : ( - obj.newValue.replace(/[[\]]/g, "") - ) - ) : ( - "--" - )} - </td> - </tr> - </tbody> - ))} - </Table> - <br /> - </> - )} - </div> - )} - - {action == "update" && !isEmpty(updateZoneServices) && ( - <div className="row"> - <div className="col"> - <h5 className="bold wrap-header m-t-sm"> - Old Zone Service Details: - </h5> + "--" + )} + </td> + <td className="table-warning text-nowrap"> + {!isEmpty(obj.newValue.replace(/[[\]]/g, "")) ? ( + isEmpty( + obj.previousValue.replace(/[[\]]/g, "") + ) ? ( + <h6> + <Badge + className="d-inline mr-1" + variant="success" + > + {obj.newValue.replace(/[[\]]/g, "")} + </Badge> + </h6> + ) : ( + obj.newValue.replace(/[[\]]/g, "") + ) + ) : ( + "--" + )} + </td> + </tr> + </tbody> + ))} + </Table> + <br /> + </> + )} + </div> + {(!isEmpty(Object.keys(updateZoneOldServices[0] || {})) || + !isEmpty(Object.keys(updateZoneNewServices[0] || {}))) && ( + <div className="row"> + <div className="col"> + <h5 className="bold wrap-header m-t-sm"> + Old Zone Service Details: + </h5> - <Table className="table table-bordered table-striped w-100"> - <thead className="thead-light"> - <tr> - <th>Service Name</th> + <Table className="table table-bordered table-striped w-100"> + <thead className="thead-light"> + <tr> + <th>Service Name</th> - <th> Zone Service Resources</th> - </tr> - </thead> - {updateZoneServices.map((key) => { - return ( - !isEmpty(key.previousValue) && - Object.keys(JSON.parse(key.previousValue)).map((c) => { - return ( + <th> Zone Service Resources</th> + </tr> + </thead> + {!isEmpty(Object.keys(updateZoneOldServices[0] || {})) ? ( + Object.entries(updateZoneOldServices[0]).map(([key]) => { + return ( + <tbody> + <tr> + <td className="old-value-bg"> + <strong> {key}</strong> + </td> + {!isEmpty( + updateZoneOldServices[0][key].resources + ) ? ( + <td className="old-value-bg"> + {Object.values( + updateZoneOldServices[0][key].resources + ).map((resource) => ( + <div className="zone-resource"> + {Object.keys(resource).map((policy) => { + return ( + <> + <strong>{`${policy} : `}</strong> + {resource[policy].join(", ")} + <br /> + </> + ); + })} + </div> + ))} + </td> + ) : ( + <td className="text-center old-value-bg">--</td> + )} + </tr> + </tbody> + ); + }) + ) : ( <tbody> <tr> - <td className="old-value-bg"> - <strong> {c}</strong> - </td> - <td className="old-value-bg"> - {Object.values( - JSON.parse(key.previousValue)[c].resources - ).map((resource) => ( - <div className="zone-resource"> - {Object.keys(resource).map((policy) => { - return ( - <> - <strong>{`${policy} : `}</strong> - {resource[policy].join(", ")} - <br /> - </> - ); - })} - </div> - ))} + <td colSpan={2} className="text-center old-value-bg"> + -- </td> </tr> </tbody> - ); - }) - ); - })} - </Table> - </div> - <div className="col"> - <h5 className="bold wrap-header m-t-sm"> - New Zone Service Details: - </h5> + )} + </Table> + </div> + <div className="col"> + <h5 className="bold wrap-header m-t-sm"> + New Zone Service Details: + </h5> - <Table className="table table-bordered table-striped w-100"> - <thead className="thead-light"> - <tr> - <th>Service Name </th> + <Table className="table table-bordered table-striped w-100"> + <thead className="thead-light"> + <tr> + <th>Service Name </th> - <th> Zone Service Resources</th> - </tr> - </thead> - {updateZoneServices.map((key) => { - return ( - !isEmpty(key.newValue) && - Object.keys(JSON.parse(key.newValue)).map((c) => { - return ( + <th> Zone Service Resources</th> + </tr> + </thead> + {!isEmpty(Object.keys(updateZoneNewServices[0] || {})) ? ( + Object.entries(updateZoneNewServices[0]).map(([key]) => { + return ( + <tbody> + <tr> + <td className="table-warning align-middle"> + <strong> {key}</strong> + </td> + {!isEmpty( + updateZoneNewServices[0][key].resources + ) ? ( + <td className="table-warning "> + {Object.values( + updateZoneNewServices[0][key].resources + ).map((resource) => ( + <div className="zone-resource"> + {Object.keys(resource).map((policy) => { + return ( + <> + <strong>{`${policy} : `}</strong> + {resource[policy].join(", ")} + <br /> + </> + ); + })} + </div> + ))} + </td> + ) : ( + <td className="text-center table-warning"> + -- + </td> + )} + </tr> + </tbody> + ); + }) + ) : ( <tbody> <tr> - <td className="table-warning align-middle"> - <strong> {c}</strong> - </td> - <td className="table-warning "> - {Object.values( - JSON.parse(key.newValue)[c].resources - ).map((resource) => ( - <div className="zone-resource"> - {Object.keys(resource).map((policy) => { - return ( - <> - <strong>{`${policy} : `}</strong> - {resource[policy].join(", ")} - <br /> - </> - ); - })} - </div> - ))} + <td colSpan={2} className="text-center table-warning"> + -- </td> </tr> </tbody> - ); - }) - ); - })} - </Table> - <br /> - </div> - </div> - )} + )} + </Table> + <br /> + </div> + </div> + )} + </> + )} {/* DELETE */} @@ -360,31 +431,31 @@ export const SecurityZonelogs = ({ data, reportdata }) => { })} </Table> <br /> - <h5 className="bold wrap-header m-t-sm">Zone Service Details:</h5> - <Table className="table table-striped table-bordered w-75"> - <thead className="thead-light"> - <tr> - <th>Service Name</th> + {!isEmpty(Object.keys(oldZoneServiceData[0] || {})) && ( + <> + <h5 className="bold wrap-header m-t-sm"> + Zone Service Details: + </h5> + <Table className="table table-striped table-bordered w-75"> + <thead className="thead-light"> + <tr> + <th>Service Name</th> - <th>Zone Service Resources</th> - </tr> - </thead> + <th>Zone Service Resources</th> + </tr> + </thead> - {reportdata - .filter((obj) => obj.attributeName == "Zone Services") - .map((key) => { - return ( - !isEmpty(key.previousValue) && - Object.keys(JSON.parse(key.previousValue)).map((c) => { - return ( - <tbody> - <tr> - <td className="table-warning align-middle"> - <strong> {c}</strong> - </td> + {Object.entries(oldZoneServiceData[0]).map(([key]) => { + return ( + <tbody> + <tr> + <td className="table-warning align-middle"> + <strong> {key}</strong> + </td> + {!isEmpty(oldZoneServiceData[0][key].resources) ? ( <td className="table-warning"> {Object.values( - JSON.parse(key.previousValue)[c].resources + oldZoneServiceData[0][key].resources ).map((resource) => ( <div className="zone-resource"> {Object.keys(resource).map((policy) => { @@ -399,13 +470,16 @@ export const SecurityZonelogs = ({ data, reportdata }) => { </div> ))} </td> - </tr> - </tbody> - ); - }) - ); - })} - </Table> + ) : ( + <td className="text-center table-warning">--</td> + )} + </tr> + </tbody> + ); + })} + </Table> + </> + )} </div> )} </div> diff --git a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/OperationAdminModal.jsx b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/OperationAdminModal.jsx index 8e17b4301..0d30e3224 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/OperationAdminModal.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/OperationAdminModal.jsx @@ -43,17 +43,20 @@ export const OperationAdminModal = ({ onHide, show, data = {} }) => { const rowModal = async () => { setLoader(true); + let authlogs = []; + try { const authResp = await fetchApi({ url: `assets/report/${transactionId}` }); - let authlogs = authResp.data.vXTrxLogs; - setShowview(objectId); - setReportData(authlogs); - setLoader(false); + authlogs = authResp?.data?.vXTrxLogs || []; } catch (error) { console.error(`Error occurred while fetching Admin logs! ${error}`); } + + setShowview(objectId); + setReportData(authlogs); + setLoader(false); }; return ( diff --git a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx index fc56b661c..3bf0df71c 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx @@ -124,14 +124,6 @@ const SecurityZoneForm = () => { text: "" }; } - - if (isEmpty(values.resourceServices)) { - errors.resourceServices = { - required: true, - text: "Required" - }; - } - return errors; }; @@ -325,33 +317,29 @@ const SecurityZoneForm = () => { } zoneData.services = {}; - - for (let key of Object.keys(values.tableList)) { - let serviceName = values.tableList[key].serviceName; - let resourcesName = values.tableList[key].resources; - zoneData.services[serviceName] = {}; - zoneData.services[serviceName].resources = []; - resourcesName.map((obj) => { - let serviceResourceData = {}; - pickBy(obj, (key, val) => { - if ( - obj[`value-${key.level}`] && - obj[`value-${key.level}`].length > 0 - ) { - if (val.includes("resourceName")) { - serviceResourceData[key.name] = obj[`value-${key.level}`].map( - (value) => value.value - ); + if (!isEmpty(Object.keys(values.tableList || {}))) { + for (let key of Object.keys(values.tableList)) { + let serviceName = values.tableList[key].serviceName; + let resourcesName = values.tableList[key].resources; + zoneData.services[serviceName] = {}; + zoneData.services[serviceName].resources = []; + resourcesName.map((obj) => { + let serviceResourceData = {}; + pickBy(obj, (key, val) => { + if ( + obj[`value-${key.level}`] && + obj[`value-${key.level}`].length > 0 + ) { + if (val.includes("resourceName")) { + serviceResourceData[key.name] = obj[`value-${key.level}`].map( + (value) => value.value + ); + } } - } - }); - return zoneData.services[serviceName].resources.push( - serviceResourceData - ); - }); - if (zoneData.services[serviceName].resources.length === 0) { - toast.error("Please add at least one resource for service", { - toastId: "error1" + }); + return zoneData.services[serviceName].resources.push( + serviceResourceData + ); }); } } @@ -431,7 +419,7 @@ const SecurityZoneForm = () => { } zoneData.tableList = []; - for (let name of Object.keys(zone.services)) { + for (let name of Object.keys(zone.services || {})) { let tableValues = {}; tableValues["serviceName"] = name; @@ -450,33 +438,36 @@ const SecurityZoneForm = () => { } tableValues["resources"] = []; - zone.services[name].resources.map((obj) => { - let serviceResource = {}; - let lastResourceLevel = []; - Object.entries(obj).map(([key, value]) => { - let setResources = find(filterServiceDef.resources, ["name", key]); - serviceResource[`resourceName-${setResources.level}`] = setResources; - serviceResource[`value-${setResources.level}`] = value.map((m) => { - return { label: m, value: m }; - }); - lastResourceLevel.push({ - level: setResources.level, - name: setResources.name + if (!isEmpty(zone.services[name].resources)) { + zone.services[name].resources?.map((obj) => { + let serviceResource = {}; + let lastResourceLevel = []; + Object.entries(obj).map(([key, value]) => { + let setResources = find(filterServiceDef.resources, ["name", key]); + serviceResource[`resourceName-${setResources.level}`] = + setResources; + serviceResource[`value-${setResources.level}`] = value.map((m) => { + return { label: m, value: m }; + }); + lastResourceLevel.push({ + level: setResources.level, + name: setResources.name + }); }); + lastResourceLevel = maxBy(lastResourceLevel, "level"); + let setLastResources = find( + sortBy(filterServiceDef.resources, "itemId"), + ["parent", lastResourceLevel.name] + ); + if (setLastResources && setLastResources?.isValidLeaf) { + serviceResource[`resourceName-${setLastResources.level}`] = { + label: "None", + value: "none" + }; + } + tableValues["resources"].push(serviceResource); }); - lastResourceLevel = maxBy(lastResourceLevel, "level"); - let setLastResources = find( - sortBy(filterServiceDef.resources, "itemId"), - ["parent", lastResourceLevel.name] - ); - if (setLastResources && setLastResources?.isValidLeaf) { - serviceResource[`resourceName-${setLastResources.level}`] = { - label: "None", - value: "none" - }; - } - tableValues["resources"].push(serviceResource); - }); + } zoneData.tableList.push(tableValues); } @@ -930,22 +921,16 @@ const SecurityZoneForm = () => { /> <Field name="resourceServices" - render={({ input, meta }) => ( + render={({ input }) => ( <Row className="form-group"> <Col xs={3}> <label className="form-label pull-right"> - Select Resource Services * + Select Resource Services </label> </Col> <Col xs={6}> <Select {...input} - styles={ - meta.error && meta.touched - ? selectCustomStyles - : "" - } - id={meta.error && meta.touched ? "isError" : ""} onChange={(values, e) => resourceServicesOnChange( e, @@ -965,11 +950,6 @@ const SecurityZoneForm = () => { isSearchable={true} placeholder="Select Service Name" /> - {meta.error && meta.touched && ( - <span className="invalid-field"> - {meta.error.text} - </span> - )} </Col> </Row> )} diff --git a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx index db1fa0622..5a8cbe540 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx @@ -30,7 +30,7 @@ import { Modal } from "react-bootstrap"; import { Link } from "react-router-dom"; -import { find } from "lodash"; +import { find, isEmpty } from "lodash"; import { isSystemAdmin, isKeyAdmin } from "Utils/XAUtils"; class ZoneDisplay extends Component { @@ -104,7 +104,7 @@ class ZoneDisplay extends Component { {this.state.isAdminRole && ( <div className="float-right d-flex align-items-start"> <Link - className="btn btn-sm btn-outline-primary m-r-5 " + className="btn btn-sm btn-outline-primary m-r-5" title="Edit" to={`/zones/edit/${this.props.zone.id}`} data-id="editZone" @@ -181,7 +181,7 @@ class ZoneDisplay extends Component { <Accordion.Collapse eventKey="0"> <Card.Body className="p-0"> <Form className="border border-white shadow-none p-0"> - <Form.Group as={Row} className="mb-3 "> + <Form.Group as={Row} className="mb-3"> <Form.Label className="text-right" column sm="3"> Admin Users </Form.Label> @@ -210,20 +210,18 @@ class ZoneDisplay extends Component { </Form.Label> <Col sm="9" className="pt-2"> {this.props?.zone?.adminUserGroups?.length > 0 ? ( - this.props?.zone?.adminUserGroups?.map( - (obj, index) => { - return ( - <Badge - variant="secondary" - className="mr-1 more-less-width text-truncate" - key={obj} - title={obj} - > - {obj} - </Badge> - ); - } - ) + this.props?.zone?.adminUserGroups?.map((obj) => { + return ( + <Badge + variant="secondary" + className="mr-1 more-less-width text-truncate" + key={obj} + title={obj} + > + {obj} + </Badge> + ); + }) ) : ( <span className="mt-1">--</span> )} @@ -258,20 +256,18 @@ class ZoneDisplay extends Component { </Form.Label> <Col sm="9" className="pt-2"> {this.props?.zone?.auditUserGroups?.length > 0 ? ( - this.props?.zone?.auditUserGroups?.map( - (obj, index) => { - return ( - <Badge - variant="secondary" - className="mr-1 more-less-width text-truncate" - key={obj} - title={obj} - > - {obj} - </Badge> - ); - } - ) + this.props?.zone?.auditUserGroups?.map((obj) => { + return ( + <Badge + variant="secondary" + className="mr-1 more-less-width text-truncate" + key={obj} + title={obj} + > + {obj} + </Badge> + ); + }) ) : ( <span className="mt-1">--</span> )} @@ -360,44 +356,70 @@ class ZoneDisplay extends Component { </tr> </thead> <tbody> - {Object.keys(this.props?.zone?.services)?.map( - (key, index) => { - let servicetype = find(this.props.services, { - name: key - }); + {!isEmpty(this.props?.zone?.services) ? ( + Object.keys(this.props?.zone?.services)?.map( + (key, index) => { + let servicetype = find(this.props.services, { + name: key + }); - return ( - <tr className="bg-white" key={index}> - <td className="align-middle" width="20%"> - {key} - </td> - <td className="align-middle" width="20%"> - {servicetype && - servicetype.type.toUpperCase()} - </td> - <td - className="text-center" - width="32%" - height="55px" - > - {this.props?.zone?.services[ - key - ]?.resources?.map((resource, index) => ( - <div className="resource-group" key={index}> - {Object.keys(resource)?.map( - (resourceKey, index) => ( - <p key={index} className="text-break"> - <strong>{`${resourceKey} : `}</strong> - {resource[resourceKey].join(", ")} - </p> - ) - )} - </div> - ))} - </td> - </tr> - ); - } + return ( + <tr className="bg-white" key={index}> + <td className="align-middle" width="20%"> + {key} + </td> + <td className="align-middle" width="20%"> + {servicetype && + servicetype.type.toUpperCase()} + </td> + <td + className="text-center" + width="32%" + height="55px" + > + {!isEmpty( + this.props?.zone?.services[key]?.resources + ) + ? this.props?.zone?.services[ + key + ]?.resources?.map((resource, index) => ( + <div + className="resource-group" + key={index} + > + {Object.keys(resource)?.map( + (resourceKey, index) => ( + <p + key={index} + className="text-break" + > + <strong>{`${resourceKey} : `}</strong> + {resource[resourceKey].join( + ", " + )} + </p> + ) + )} + </div> + )) + : "--"} + </td> + </tr> + ); + } + ) + ) : ( + <tr> + <td + colSpan="3" + className="text-center text-secondary bg-light" + > + <h6 className="text-muted large mt-2"> + No resource based services are associated with + this zone + </h6> + </td> + </tr> )} </tbody> </Table> diff --git a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneListing.jsx b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneListing.jsx index 046a7fd8b..e672611dd 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneListing.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneListing.jsx @@ -258,7 +258,7 @@ class ZoneListing extends Component { <Col md="auto"> <div className="pt-5 pr-5"> <img - alt="Avatar" + alt="No Zones" className="w-50 p-3 d-block mx-auto" src={noZoneImage} /> diff --git a/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceDefinitions.jsx b/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceDefinitions.jsx index 715038f67..0b2f46bec 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceDefinitions.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceDefinitions.jsx @@ -18,7 +18,7 @@ */ import React, { Component } from "react"; -import { Button, Row } from "react-bootstrap"; +import { Button, Col, Row } from "react-bootstrap"; import Select from "react-select"; import { toast } from "react-toastify"; import { filter, map, sortBy, uniq, isEmpty } from "lodash"; @@ -37,6 +37,7 @@ import ImportPolicy from "./ImportPolicy"; import { serverError } from "../../utils/XAUtils"; import { BlockUi, Loader } from "../../components/CommonComponents"; import { getServiceDef } from "../../utils/appState"; +import noServiceImage from "Images/no-service.svg"; class ServiceDefinitions extends Component { constructor(props) { @@ -454,28 +455,41 @@ class ServiceDefinitions extends Component { <Loader /> ) : ( <div className="wrap policy-manager"> - <Row> - {filterServiceDefs?.map((serviceDef) => ( - <ServiceDefinition - key={serviceDef && serviceDef.id} - serviceDefData={serviceDef} - servicesData={sortBy( - filterServices.filter( - (service) => service.type === serviceDef.name - ), - "name" - )} - deleteService={this.deleteService} - selectedZone={selectedZone} - zones={zones} - isAdminRole={isAdminRole} - isUserRole={isUserRole} - showBlockUI={this.showBlockUI} - allServices={this.state.allServices} - ></ServiceDefinition> - ))} - </Row> - + {!isEmpty(filterServiceDefs) ? ( + <Row> + {filterServiceDefs?.map((serviceDef) => ( + <ServiceDefinition + key={serviceDef && serviceDef.id} + serviceDefData={serviceDef} + servicesData={sortBy( + filterServices.filter( + (service) => service.type === serviceDef.name + ), + "name" + )} + deleteService={this.deleteService} + selectedZone={selectedZone} + zones={zones} + isAdminRole={isAdminRole} + isUserRole={isUserRole} + showBlockUI={this.showBlockUI} + allServices={this.state.allServices} + ></ServiceDefinition> + ))} + </Row> + ) : ( + <Row className="justify-content-md-center"> + <Col md="auto"> + <div className="pt-5 pr-5"> + <img + alt="No Services" + className="w-50 p-3 d-block mx-auto" + src={noServiceImage} + /> + </div> + </Col> + </Row> + )} <BlockUi isUiBlock={this.state.blockUI} /> </div> )}