RANGER-4641: Handling empty values while displaying ActivationTime & implementing Column Hide/Show functionality in Audit Plugin Status Module
Signed-off-by: Madhan Neethiraj <madhan@apache.org>
diff --git a/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx b/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx
index 1fca378..79fcbd1 100644
--- a/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx
@@ -441,7 +441,11 @@
export const CustomTooltip = ({ placement, content, icon }) => (
<OverlayTrigger
placement={placement}
- overlay={<Popover id={`tooltip-${placement}`}>{content}</Popover>}
+ overlay={
+ <Popover id={`tooltip-${placement}`}>
+ <span className=" d-block px-2 py-1">{content}</span>
+ </Popover>
+ }
>
<i className={icon} data-id="infoTextFiled" data-cy="infoTextFiled"></i>
</OverlayTrigger>
diff --git a/security-admin/src/main/webapp/react-webapp/src/components/XATableLayout.jsx b/security-admin/src/main/webapp/react-webapp/src/components/XATableLayout.jsx
index 71a33f1..d75315e 100644
--- a/security-admin/src/main/webapp/react-webapp/src/components/XATableLayout.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/components/XATableLayout.jsx
@@ -28,7 +28,7 @@
} from "react-table";
import { Table, ButtonGroup } from "react-bootstrap";
import DropdownButton from "react-bootstrap/DropdownButton";
-import { isEmpty } from "lodash";
+import { groupBy, isEmpty, uniq, uniqBy } from "lodash";
const IndeterminateCheckbox = forwardRef(
({ indeterminate, chkType, ...rest }, ref) => {
@@ -195,6 +195,22 @@
</span>
);
};
+ /* For Column Visibility */
+ const groupedColumnsData = groupBy(allColumns, "parent[id]");
+ delete groupedColumnsData.undefined;
+ const allColumnsData = allColumns.map((column) => {
+ const columnName = column?.parent
+ ? `Group(${column?.parent.id})`
+ : `Non-Group(${column?.id})`;
+ return {
+ columnName,
+ columnData: groupedColumnsData[column.parent?.id] || column
+ };
+ });
+
+ let filterAllColumns = uniqBy(allColumnsData, function (column) {
+ return column.columnName;
+ });
let columnShowHide = [];
return (
@@ -203,7 +219,7 @@
{columnHide && (
<div className="text-right mb-2 mt-n5">
<DropdownButton
- className="p-0"
+ className="p-0 column-dropdown"
menuAlign="right"
as={ButtonGroup}
size="sm"
@@ -211,35 +227,70 @@
variant="info"
title="Columns"
>
- <ul className="list-group">
- {allColumns.map((column, index) => {
- columnShowHide.push({
- name: column.id,
- renderable: column.isVisible
- });
+ <div className="column-dropdown-maxheight">
+ <ul className="list-group fnt-14">
+ {filterAllColumns.map((column, index) => {
+ columnShowHide.push({
+ name: column.columnData.id,
+ renderable: column.columnData.isVisible
+ });
- localStorage.setItem(
- "showHideTableCol",
- JSON.stringify({ bigData: columnShowHide })
- );
- return (
- <li
- className="column-list text-truncate"
- key={`col-${index}`}
- >
- <label>
- <input
- className="mr-1"
- type="checkbox"
- {...column.getToggleHiddenProps()}
- />
-
- {column.Header}
- </label>
- </li>
- );
- })}
- </ul>
+ localStorage.setItem(
+ "showHideTableCol",
+ JSON.stringify({ bigData: columnShowHide })
+ );
+ return column.columnName ==
+ `Non-Group(${column.columnData.id})` ? (
+ <li
+ className="column-list text-truncate"
+ key={`col-${index}`}
+ >
+ <label
+ title={column.columnData.Header}
+ className="d-flex align-items-center"
+ >
+ <input
+ className="mr-1"
+ type="checkbox"
+ {...column.columnData.getToggleHiddenProps()}
+ />
+ {column.columnData.Header}
+ </label>
+ </li>
+ ) : (
+ <li
+ className="column-list text-truncate"
+ key={`col-${index}`}
+ >
+ {column.columnName !== undefined && (
+ <div className="font-weight-bold text-secondary mb-2 fnt-14">
+ {column.columnName !== undefined &&
+ column?.columnData[0]?.parent?.id}
+ </div>
+ )}
+ {column.columnData.map((columns) => (
+ <ul key={columns.id} className="p-0">
+ <li className=" list-unstyled">
+ {" "}
+ <label
+ title={columns.Header}
+ className="d-flex align-items-center"
+ >
+ <input
+ className="mr-1"
+ type="checkbox"
+ {...columns.getToggleHiddenProps()}
+ />
+ {columns.Header}
+ </label>
+ </li>
+ </ul>
+ ))}
+ </li>
+ );
+ })}
+ </ul>
+ </div>
</DropdownButton>
</div>
)}
diff --git a/security-admin/src/main/webapp/react-webapp/src/styles/style.css b/security-admin/src/main/webapp/react-webapp/src/styles/style.css
index ed45e86..f5caff0 100755
--- a/security-admin/src/main/webapp/react-webapp/src/styles/style.css
+++ b/security-admin/src/main/webapp/react-webapp/src/styles/style.css
@@ -3032,3 +3032,13 @@
max-height: 126px;
overflow-y: scroll;
}
+
+.column-dropdown .dropdown-toggle:focus {
+ color: #fff;
+ background-color: #117a8b;
+ border-color: none;
+}
+.column-dropdown-maxheight {
+ max-height: 400px;
+ overflow-y: auto;
+}
diff --git a/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js b/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js
index 842cb69..012463e 100755
--- a/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js
+++ b/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js
@@ -893,3 +893,26 @@
groupSearchFirstEnabled: "Group search first enabled",
groupHierarchyLevel: "Group hierarchy level"
};
+
+export const pluginStatusColumnInfoMsg = {
+ Policy: {
+ title: "Policy (Time details)",
+ lastUpdated: "Last updated time of policy.",
+ downloadTime: "Time when policy actually downloaded(sync-up with Ranger).",
+ activeTime: "Time when policy actually in use for enforcement.",
+ downloadTimeDelayMsg:
+ "Policy is updated but not yet downloaded(sync-up with Ranger).",
+ activationTimeDelayMsg:
+ "Policy is updated but not yet used for any enforcement."
+ },
+ Tag: {
+ title: "Tag Policy (Time details)",
+ lastUpdated: "Last updated time of Tag-service.",
+ downloadTime: "Time when tag-based policies sync-up with Ranger.",
+ activeTime: "Time when tag-based policies in use for enforcement.",
+ downloadTimeDelayMsg:
+ "Policy is updated but not yet downloaded(sync-up with Ranger).",
+ activationTimeDelayMsg:
+ "Policy is updated but not yet used for any enforcement."
+ }
+};
diff --git a/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js b/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js
index d22ecfa..ee7b010 100644
--- a/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js
+++ b/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js
@@ -18,6 +18,7 @@
*/
import React from "react";
+import { pluginStatusColumnInfoMsg } from "./XAEnums";
export const RegexMessage = {
MESSAGE: {
@@ -129,3 +130,24 @@
</p>
);
};
+
+/* PluginStatus Column Info */
+
+export const pluginStatusColumnInfo = (colName) => {
+ return (
+ <ul className="list-inline">
+ <li className="list-inline-item">
+ <strong>Last Update: </strong>{" "}
+ {pluginStatusColumnInfoMsg[colName].lastUpdated}
+ </li>
+ <li className="list-inline-item">
+ <strong>Download: </strong>
+ {pluginStatusColumnInfoMsg[colName].downloadTime}
+ </li>
+ <li className="list-inline-item">
+ <strong>Active: </strong>{" "}
+ {pluginStatusColumnInfoMsg[colName].activeTime}
+ </li>
+ </ul>
+ );
+};
diff --git a/security-admin/src/main/webapp/react-webapp/src/utils/XAUtils.js b/security-admin/src/main/webapp/react-webapp/src/utils/XAUtils.js
index f834f97..d189e4a 100644
--- a/security-admin/src/main/webapp/react-webapp/src/utils/XAUtils.js
+++ b/security-admin/src/main/webapp/react-webapp/src/utils/XAUtils.js
@@ -198,7 +198,9 @@
<span title={formatDateTime}>
{formatDateTime}
<div className="text-muted">
- <small>{moment(formatDateTime).fromNow()}</small>
+ <small>
+ {moment(formatDateTime, "MM/DD/YYYY h:mm:ss A").fromNow()}
+ </small>
</div>
</span>
) : (
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginStatusLogs.jsx b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginStatusLogs.jsx
index 07ac391..6380782 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginStatusLogs.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginStatusLogs.jsx
@@ -23,7 +23,6 @@
import XATableLayout from "Components/XATableLayout";
import { AuditFilterEntries } from "Components/CommonComponents";
import moment from "moment-timezone";
-import dateFormat from "dateformat";
import {
setTimeStamp,
fetchSearchFilterParams,
@@ -39,8 +38,18 @@
} from "../../components/CommonComponents";
import StructuredFilter from "../../components/structured-filter/react-typeahead/tokenizer";
import { fetchApi } from "Utils/fetchAPI";
-import { isUndefined, map, sortBy, toUpper, filter } from "lodash";
+import {
+ isUndefined,
+ map,
+ sortBy,
+ toUpper,
+ filter,
+ isNull,
+ isEmpty
+} from "lodash";
import { getServiceDef } from "../../utils/appState";
+import { pluginStatusColumnInfo } from "../../utils/XAMessages";
+import { pluginStatusColumnInfoMsg } from "../../utils/XAEnums";
function Plugin_Status() {
const context = useOutletContext();
@@ -120,49 +129,111 @@
return diff < 0 ? true : false;
};
+ const getLastUpdateTime = (lastUpdateTime) => {
+ if (isUndefined(lastUpdateTime) || isNull(lastUpdateTime)) {
+ return <center>--</center>;
+ }
+ return setTimeStamp(lastUpdateTime);
+ };
+
+ const getDownloadTime = (downloadTime, lastUpdateTime, columnsName) => {
+ if (isUndefined(downloadTime) || isNull(downloadTime)) {
+ return <center>--</center>;
+ }
+
+ if (!isUndefined(lastUpdateTime)) {
+ let downloadDate = new Date(parseInt(downloadTime));
+ let lastUpdateDate = new Date(parseInt(lastUpdateTime));
+ if (isDateDifferenceMoreThanHr(downloadDate, lastUpdateDate)) {
+ if (
+ moment(downloadDate).diff(moment(lastUpdateDate), "minutes") >= -2
+ ) {
+ return (
+ <span className="text-warning">
+ <CustomTooltip
+ placement="bottom"
+ content={
+ pluginStatusColumnInfoMsg[columnsName].downloadTimeDelayMsg
+ }
+ icon="fa-fw fa fa-exclamation-circle active-policy-alert"
+ />
+ {setTimeStamp(downloadTime)}
+ </span>
+ );
+ } else {
+ return (
+ <span className="text-error">
+ <CustomTooltip
+ placement="bottom"
+ content={
+ pluginStatusColumnInfoMsg[columnsName].downloadTimeDelayMsg
+ }
+ icon="fa-fw fa fa-exclamation-circle active-policy-alert"
+ />
+ {setTimeStamp(downloadTime)}{" "}
+ </span>
+ );
+ }
+ }
+ }
+ return setTimeStamp(downloadTime);
+ };
+
+ const getActivationTime = (activeTime, lastUdpateTime, columnsName) => {
+ if (isUndefined(activeTime) || isNull(activeTime) || activeTime == 0) {
+ return <center>--</center>;
+ }
+ if (!isUndefined(lastUdpateTime)) {
+ let activeDate = new Date(parseInt(activeTime));
+ let lastUpdateDate = new Date(parseInt(lastUdpateTime));
+ if (isDateDifferenceMoreThanHr(activeDate, lastUpdateDate)) {
+ if (moment(activeDate).diff(moment(lastUpdateDate), "minutes") >= -2) {
+ return (
+ <span className="text-warning">
+ <CustomTooltip
+ placement="bottom"
+ content={
+ pluginStatusColumnInfoMsg[columnsName].activationTimeDelayMsg
+ }
+ icon="fa-fw fa fa-exclamation-circle active-policy-alert"
+ />
+ {setTimeStamp(activeTime)}
+ </span>
+ );
+ } else {
+ return (
+ <span className="text-error">
+ <CustomTooltip
+ placement="bottom"
+ content={
+ pluginStatusColumnInfoMsg[columnsName].activationTimeDelayMsg
+ }
+ icon="fa-fw fa fa-exclamation-circle active-policy-alert"
+ />
+ {setTimeStamp(activeTime)}
+ </span>
+ );
+ }
+ }
+ }
+ return setTimeStamp(activeTime);
+ };
+
const refreshTable = () => {
setPluginStatusLogs([]);
setLoader(true);
setUpdateTable(moment.now());
};
- const contents = (val) => {
+ const infoIcon = (columnsName) => {
return (
<>
- <ul className="list-inline">
- <li className="list-inline-item">
- <strong>Last Update: </strong> Last updated time of{" "}
- {val == "Tag" ? "Tag-service" : "policy"}.
- </li>
- <li className="list-inline-item">
- <strong>Download: </strong>
- {val == "Tag"
- ? "Time when tag-based policies sync-up with Ranger."
- : "Time when policy actually downloaded(sync-up with Ranger)."}
- </li>
- <li className="list-inline-item">
- <strong>Active: </strong> Time when{" "}
- {val == "Tag" ? "tag-based" : "policy"} actually in use for
- enforcement.
- </li>
- </ul>
- </>
- );
- };
-
- const infoIcon = (val) => {
- return (
- <>
- <b>{val} ( Time )</b>
+ <b>{columnsName} ( Time )</b>
<CustomPopover
icon="fa-fw fa fa-info-circle info-icon"
- title={
- val == "Policy"
- ? "Policy (Time details)"
- : "Tag Policy (Time details)"
- }
- content={contents(val)}
+ title={pluginStatusColumnInfoMsg[columnsName].title}
+ content={pluginStatusColumnInfo(columnsName)}
placement="left"
trigger={["hover", "focus"]}
/>
@@ -217,18 +288,18 @@
accessor: "clusterName",
Cell: ({ row: { original } }) => {
let clusterName = original?.info?.clusterName;
- return isUndefined(clusterName) ? "--" : clusterName;
+ return !isEmpty(clusterName) ? clusterName : <center>--</center>;
}
},
{
Header: infoIcon("Policy"),
- id: "policyinfo",
+ id: "Policy (Time)",
columns: [
{
Header: "Last Update",
accessor: "lastPolicyUpdateTime",
Cell: ({ row: { original } }) => {
- return setTimeStamp(original.info.lastPolicyUpdateTime);
+ return getLastUpdateTime(original.info.lastPolicyUpdateTime);
},
minWidth: 190
},
@@ -236,54 +307,11 @@
Header: "Download",
accessor: "policyDownloadTime",
Cell: ({ row: { original } }) => {
- var downloadDate = new Date(
- parseInt(original.info.policyDownloadTime)
+ return getDownloadTime(
+ original.info.policyDownloadTime,
+ original.info.lastPolicyUpdateTime,
+ "Policy"
);
-
- dateFormat(
- parseInt(original.info.policyDownloadTime),
- "mm/dd/yyyy hh:MM:ss TT"
- );
- if (!isUndefined(original.info.lastPolicyUpdateTime)) {
- var lastUpdateDate = new Date(
- parseInt(original.info.lastPolicyUpdateTime)
- );
- if (isDateDifferenceMoreThanHr(downloadDate, lastUpdateDate)) {
- if (
- moment(downloadDate).diff(
- moment(lastUpdateDate),
- "minutes"
- ) >= -2
- ) {
- return (
- <span className="text-warning">
- <CustomTooltip
- placement="bottom"
- content={
- "Policy is updated but not yet downloaded(sync-upwith Ranger)"
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.policyDownloadTime)}
- </span>
- );
- } else {
- return (
- <span className="text-error">
- <CustomTooltip
- placement="bottom"
- content={
- "Policy is updated but not yet downloaded(sync-upwith Ranger)"
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.policyDownloadTime)}{" "}
- </span>
- );
- }
- }
- }
- return setTimeStamp(original.info.policyDownloadTime);
},
minWidth: 190
},
@@ -291,51 +319,11 @@
Header: "Active",
accessor: "policyActivationTime",
Cell: ({ row: { original } }) => {
- let activeDate = new Date(
- parseInt(original.info.policyActivationTime)
+ return getActivationTime(
+ original.info.policyActivationTime,
+ original.info.lastPolicyUpdateTime,
+ "Policy"
);
-
- if (!isUndefined(original.info.lastPolicyUpdateTime)) {
- let lastUpdateDate = new Date(
- parseInt(original.info.lastPolicyUpdateTime)
- );
-
- if (isDateDifferenceMoreThanHr(activeDate, lastUpdateDate)) {
- if (
- moment(activeDate).diff(
- moment(lastUpdateDate),
- "minutes"
- ) >= -2
- ) {
- return (
- <span className="text-warning">
- <CustomTooltip
- placement="bottom"
- content={
- " Policy is updated but not yet used for any enforcement."
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.policyActivationTime)}
- </span>
- );
- } else {
- return (
- <span className="text-error">
- <CustomTooltip
- placement="bottom"
- content={
- " Policy is updated but not yet used for any enforcement."
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.policyActivationTime)}
- </span>
- );
- }
- }
- }
- return setTimeStamp(original.info.policyActivationTime);
},
minWidth: 190
}
@@ -343,13 +331,13 @@
},
{
Header: infoIcon("Tag"),
- id: "taginfo",
+ id: "Tag (Time)",
columns: [
{
Header: "Last Update",
accessor: "lastTagUpdateTime",
Cell: ({ row: { original } }) => {
- return setTimeStamp(original.info.lastTagUpdateTime);
+ return getLastUpdateTime(original.info.lastTagUpdateTime);
},
minWidth: 190
},
@@ -358,50 +346,11 @@
accessor: "tagDownloadTime",
Cell: ({ row: { original } }) => {
- var downloadDate = new Date(
- parseInt(original.info.tagDownloadTime)
+ return getDownloadTime(
+ original.info.tagDownloadTime,
+ original.info.lastTagUpdateTime,
+ "Tag"
);
-
- if (!isUndefined(original.info.lastTagUpdateTime)) {
- var lastUpdateDate = new Date(
- parseInt(original.info.lastTagUpdateTime)
- );
- if (isDateDifferenceMoreThanHr(downloadDate, lastUpdateDate)) {
- if (
- moment(downloadDate).diff(
- moment(lastUpdateDate),
- "minutes"
- ) >= -2
- ) {
- return (
- <span className="text-warning">
- <CustomTooltip
- placement="bottom"
- content={
- "Policy is updated but not yet downloaded(sync-upwith Ranger)"
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.tagDownloadTime)}
- </span>
- );
- } else {
- return (
- <span className="text-error">
- <CustomTooltip
- placement="bottom"
- content={
- "Policy is updated but not yet downloaded(sync-upwith Ranger)"
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.tagDownloadTime)}{" "}
- </span>
- );
- }
- }
- }
- return setTimeStamp(original.info.tagDownloadTime);
},
minWidth: 190
},
@@ -410,50 +359,11 @@
accessor: "tagActivationTime",
Cell: ({ row: { original } }) => {
- var downloadDate = new Date(
- parseInt(original.info.tagActivationTime)
+ return getActivationTime(
+ original.info.tagActivationTime,
+ original.info.lastTagUpdateTime,
+ "Tag"
);
-
- if (!isUndefined(original.info.lastTagUpdateTime)) {
- var lastUpdateDate = new Date(
- parseInt(original.info.lastTagUpdateTime)
- );
- if (isDateDifferenceMoreThanHr(downloadDate, lastUpdateDate)) {
- if (
- moment(downloadDate).diff(
- moment(lastUpdateDate),
- "minutes"
- ) >= -2
- ) {
- return (
- <span className="text-warning">
- <CustomTooltip
- placement="bottom"
- content={
- "Policy is updated but not yet used for anyenforcement."
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.tagActivationTime)}
- </span>
- );
- } else {
- return (
- <span className="text-error">
- <CustomTooltip
- placement="bottom"
- content={
- "Policy is updated but not yet used for anyenforcement."
- }
- icon="fa-fw fa fa-exclamation-circle active-policy-alert"
- />
- {setTimeStamp(original.info.tagActivationTime)}{" "}
- </span>
- );
- }
- }
- }
- return setTimeStamp(original.info.tagActivationTime);
},
minWidth: 190
}
@@ -564,7 +474,11 @@
</div>
</Col>
</Row>
- <AuditFilterEntries entries={entries} refreshTable={refreshTable} />
+ <Row>
+ <Col sm={11}>
+ <AuditFilterEntries entries={entries} refreshTable={refreshTable} />
+ </Col>
+ </Row>
<XATableLayout
data={pluginStatusListingData}
columns={columns}
@@ -574,6 +488,7 @@
columnSort={true}
clientSideSorting={true}
showPagination={false}
+ columnHide={true}
/>
</React.Fragment>
</div>
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginsLog.jsx b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginsLog.jsx
index 53e5079..d6f8b43 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginsLog.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/PluginsLog.jsx
@@ -24,7 +24,7 @@
import { AuditFilterEntries } from "Components/CommonComponents";
import moment from "moment-timezone";
import dateFormat from "dateformat";
-import { sortBy, filter } from "lodash";
+import { sortBy, filter, isEmpty } from "lodash";
import StructuredFilter from "../../components/structured-filter/react-typeahead/tokenizer";
import { fetchApi } from "Utils/fetchAPI";
import {
@@ -168,13 +168,15 @@
Header: "Plugin ID",
accessor: "agentId",
Cell: (rawValue) => {
- return (
+ return !isEmpty(rawValue.value) ? (
<span
className="text-truncate text-center d-block"
title={rawValue.value}
>
{rawValue.value}
</span>
+ ) : (
+ <span className="text-center d-block">--</span>
);
},
disableSortBy: true
@@ -198,13 +200,15 @@
Header: "Cluster Name",
accessor: "clusterName",
Cell: (rawValue) => {
- return (
+ return !isEmpty(rawValue.value) ? (
<span
className="text-truncate text-center d-block"
title={rawValue.value}
>
{rawValue.value}
</span>
+ ) : (
+ <span className="text-center d-block">--</span>
);
},
width: 100,