This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch RANGER-3923
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/RANGER-3923 by this push:
new 0e36d4252 RANGER-4283: GDS UI - datashare detailed view updates
0e36d4252 is described below
commit 0e36d4252353b233a1f41348e5eb341c1939ce7c
Author: Anand Nadar <[email protected]>
AuthorDate: Fri Dec 29 11:17:57 2023 -0800
RANGER-4283: GDS UI - datashare detailed view updates
Signed-off-by: Madhan Neethiraj <[email protected]>
---
.../main/webapp/react-webapp/src/utils/XAUtils.js | 4 +
.../views/GovernedData/Dataset/AccessGrantForm.jsx | 149 ++++++----
.../GovernedData/Dataset/DatasetDetailLayout.jsx | 71 +++--
.../Dataset/PrinciplePermissionComp.jsx | 109 +++----
.../GovernedData/Datashare/AddDatashareView.jsx | 13 +-
.../Datashare/AddSharedResourceComp.jsx | 3 +-
.../Datashare/DatashareDetailLayout.jsx | 327 ++++++++++++++++++---
7 files changed, 493 insertions(+), 183 deletions(-)
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 030fb596f..f834f9795 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
@@ -1564,3 +1564,7 @@ export const getServiceDefIcon = (serviceDefName) => {
</span>
);
};
+
+export const capitalizeFirstLetter = (str) => {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+};
diff --git
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx
index 203f40258..c8120bb68 100755
---
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx
+++
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx
@@ -28,7 +28,8 @@ import {
drop,
dragOver,
getAllTimeZoneList,
- policyConditionUpdatedJSON
+ policyConditionUpdatedJSON,
+ isSystemAdmin
} from "../../../utils/XAUtils";
import { fetchApi } from "Utils/fetchAPI";
import { maxBy, find, isEmpty, isArray, isEqual, isObject } from "lodash";
@@ -66,7 +67,12 @@ function reducer(state, action) {
}
}
-function AccessGrantForm({ dataset, onDataChange, serviceCompDetails }) {
+function AccessGrantForm({
+ dataset,
+ onDataChange,
+ serviceCompDetails,
+ isAdmin
+}) {
const [policyState, dispatch] = useReducer(reducer, initialState);
const { loader, policyData, formData } = policyState;
const [showModal, policyConditionState] = useState(false);
@@ -349,6 +355,15 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
modifiedVal = true;
break;
}
+ if (
+ dirtyFieldVal == "policyItems" &&
+ values.policyItems.length == 1 &&
+ values.policyItems[0] == undefined
+ ) {
+ } else if (!isEqual(values.policyItems, initialValues.policyItems)) {
+ modifiedVal = true;
+ break;
+ }
}
}
if (
@@ -475,29 +490,33 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
>
Grants
</p>
- <div className="d-flex gap-half">
- {(values.conditions == undefined ||
- isEmpty(values.conditions)) && (
- <Button
- className="btn btn-sm"
- onClick={() => {
- policyConditionState(true);
- }}
- data-js="customPolicyConditions"
- data-cy="customPolicyConditions"
- variant="secondary"
- >
- Add Conditions
- </Button>
- )}
- {(validityPeriod == undefined ||
- validityPeriod.length == 0) && (
- <PolicyValidityPeriodComp
- addPolicyItem={addPolicyItem}
- isGDS={true}
- />
- )}
- </div>
+ {isAdmin ? (
+ <div className="d-flex gap-half">
+ {(values.conditions == undefined ||
+ isEmpty(values.conditions)) && (
+ <Button
+ className="btn btn-sm"
+ onClick={() => {
+ policyConditionState(true);
+ }}
+ data-js="customPolicyConditions"
+ data-cy="customPolicyConditions"
+ variant="secondary"
+ >
+ Add Conditions
+ </Button>
+ )}
+ {(validityPeriod == undefined ||
+ validityPeriod.length == 0) && (
+ <PolicyValidityPeriodComp
+ addPolicyItem={addPolicyItem}
+ isGDS={true}
+ />
+ )}
+ </div>
+ ) : (
+ <></>
+ )}
</div>
<div className="drag-drop-wrap pt-3">
<FieldArray name="policyItems">
@@ -532,6 +551,7 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
{...input}
placeholder="Select users,
groups, roles"
isMulti
+ isDisabled={!isAdmin}
loadOptions={fetchPrincipleData}
data-name="usersSeusersPrinciplelect"
data-cy="usersPrinciple"
@@ -553,6 +573,7 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
placeholder="Permissions"
isClearable
isMulti
+ isDisabled={!isAdmin}
/>
</div>
)}
@@ -595,21 +616,25 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
)}
</div>
</div>
- <div>
- <Button
- variant="danger"
- size="sm"
- title="Remove"
- onClick={() => {
- fields.remove(index);
- onRemovingPolicyItem();
- }}
- data-action="delete"
- data-cy="delete"
- >
- <i className="fa-fw fa fa-remove"></i>
- </Button>
- </div>
+ {isAdmin ? (
+ <div>
+ <Button
+ variant="danger"
+ size="sm"
+ title="Remove"
+ onClick={() => {
+ fields.remove(index);
+ onRemovingPolicyItem();
+ }}
+ data-action="delete"
+ data-cy="delete"
+ >
+ <i className="fa-fw fa
fa-remove"></i>
+ </Button>
+ </div>
+ ) : (
+ <></>
+ )}
</div>
</tr>
</table>
@@ -617,17 +642,23 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
}
</FieldArray>
</div>
- <Button
- className="btn btn-sm mt-2 mg-l-32 mb-5"
- type="button"
- onClick={() => addPolicyItem("policyItems", undefined)}
- data-action="addGroup"
- data-cy="addGroup"
- title="Add"
- ref={addPolicyItemClickRef}
- >
- Add More
- </Button>
+ {isAdmin ? (
+ <Button
+ className="btn btn-sm mt-2 mg-l-32 mb-5"
+ type="button"
+ onClick={() =>
+ addPolicyItem("policyItems", undefined)
+ }
+ data-action="addGroup"
+ data-cy="addGroup"
+ title="Add"
+ ref={addPolicyItemClickRef}
+ >
+ Add More
+ </Button>
+ ) : (
+ <></>
+ )}
{values?.conditions && !isEmpty(values.conditions) && (
<div className="gds-action-card mb-5 pl-0 pr-0">
@@ -685,7 +716,7 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
})}
</div>
)}
- {showModal && (
+ {isAdmin && showModal && (
<Field
className="form-control"
name="conditions"
@@ -709,11 +740,15 @@ function AccessGrantForm({ dataset, onDataChange,
serviceCompDetails }) {
<p className="gds-card-heading">
Validity Period
</p>
- <PolicyValidityPeriodComp
- addPolicyItem={addPolicyItem}
- editValidityPeriod={true}
- isGDS={true}
- />
+ {isAdmin ? (
+ <PolicyValidityPeriodComp
+ addPolicyItem={addPolicyItem}
+ editValidityPeriod={true}
+ isGDS={true}
+ />
+ ) : (
+ <></>
+ )}
</div>
{validityPeriod.map((obj, index) => {
return (
diff --git
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/DatasetDetailLayout.jsx
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/DatasetDetailLayout.jsx
index 95f06c93d..a08faba49 100755
---
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/DatasetDetailLayout.jsx
+++
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/DatasetDetailLayout.jsx
@@ -181,21 +181,46 @@ const DatasetDetailLayout = () => {
DENIED: 0
});
- const fetchShareStatusMetrics = async () => {
+ const fetchShareStatusMetrics = async (requestSearchFilterParams) => {
try {
setLoader(true);
- let params = {};
+ let requestList = [];
+ let params =
+ requestSearchFilterParams != undefined
+ ? { ...requestSearchFilterParams }
+ : {};
+ params["pageSize"] = 999999999;
params["datasetId"] = datasetId;
- const resp = await fetchApi({
- url: `gds/dataset/summary`,
- params: params
- });
- let datashareReqList = resp.data.list[0].dataShares;
+ try {
+ let resp = await fetchApi({
+ url: "gds/datashare/summary",
+ params: params
+ });
+ if (resp.data.list.length > 0) {
+ requestList = resp.data.list;
+ requestList?.forEach((datashare) => {
+ for (let i = 0; i < datashare.datasets.length; i++) {
+ if (datashare.datasets[i].datasetId == datasetId) {
+ datashare.shareStatus = datashare.datasets[i].shareStatus;
+ datashare.requestId = datashare.datasets[i].id;
+ datashare.datasetName = datashare.datasets[i].datasetName;
+ break;
+ }
+ }
+ });
+ }
+ } catch (error) {
+ serverError(error);
+ console.error(
+ `Error occurred while fetching Datashare request metrics! ${error}`
+ );
+ }
+
let activeCount = 0;
let requestedCount = 0;
let grantedCount = 0;
let deniedCount = 0;
- datashareReqList.forEach((request) => {
+ requestList.forEach((request) => {
switch (request.shareStatus) {
case "REQUESTED":
requestedCount += 1;
@@ -212,7 +237,7 @@ const DatasetDetailLayout = () => {
}
});
setShareStatusMetrics({
- totalCount: datashareReqList.length,
+ totalCount: requestList.length,
REQUESTED: requestedCount,
GRANTED: grantedCount,
ACTIVE: activeCount,
@@ -281,9 +306,9 @@ const DatasetDetailLayout = () => {
type: "text"
},
{
- category: "ZoneNamePartial",
+ category: "zoneNamePartial",
label: "Zone",
- urlLabel: "ZoneNamePartial",
+ urlLabel: "zoneNamePartial",
type: "text"
}
];
@@ -294,6 +319,7 @@ const DatasetDetailLayout = () => {
requestSearchFilterOptions
);
setRequestSearchFilterParams(searchFilterParam);
+ fetchShareStatusMetrics(searchFilterParam);
};
useEffect(() => {
@@ -414,7 +440,7 @@ const DatasetDetailLayout = () => {
const userMap = new Map();
const groupMap = new Map();
const roleMap = new Map();
- grantItems.forEach((item) => {
+ grantItems?.forEach((item) => {
if (item.users !== undefined) {
item.users.forEach((user) => {
let accessList = [];
@@ -748,7 +774,7 @@ const DatasetDetailLayout = () => {
};
const handleTabSelect = (key) => {
- if (saveCancelButtons == true) {
+ if (saveCancelButtons == true && userAclPerm != "AUDIT") {
setShowConfirmModal(true);
} else {
setActiveKey(key);
@@ -816,13 +842,15 @@ const DatasetDetailLayout = () => {
};
const handleAccessGrantChange = (accessGrantData, policyData) => {
- if (accessGrantData != undefined) {
- setAccessGrantFormValues(accessGrantData);
- }
- if (policyData != undefined) {
- setPolicyData(policyData);
+ if (userAclPerm != "AUDIT") {
+ if (accessGrantData != undefined) {
+ setAccessGrantFormValues(accessGrantData);
+ }
+ if (policyData != undefined) {
+ setPolicyData(policyData);
+ }
+ showSaveCancelButton(true);
}
- showSaveCancelButton(true);
};
const updateDatasetAccessGrant = async () => {
@@ -1897,6 +1925,11 @@ const DatasetDetailLayout = () => {
dataset={datasetInfo}
onDataChange={handleAccessGrantChange}
serviceCompDetails={serviceDef}
+ isAdmin={
+ isSystemAdmin() ||
+ userAclPerm == "ADMIN" ||
+ userAclPerm == "POLICY_ADMIN"
+ }
/>
) : (
<div></div>
diff --git
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/PrinciplePermissionComp.jsx
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/PrinciplePermissionComp.jsx
index 326433e66..e3418ae64 100755
---
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/PrinciplePermissionComp.jsx
+++
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/PrinciplePermissionComp.jsx
@@ -31,6 +31,7 @@ import AsyncSelect from "react-select/async";
import { fetchApi } from "../../../utils/fetchAPI";
import { findIndex, remove } from "lodash";
import { isSystemAdmin } from "../../../utils/XAUtils";
+import { toast } from "react-toastify";
const initialState = {
selectedPrinciple: []
@@ -90,16 +91,10 @@ const PrinciplePermissionComp = ({
{ value: "VIEW", label: "VIEW" },
{ value: "AUDIT", label: "AUDIT" },
{ value: "POLICY_ADMIN", label: "POLICY_ADMIN" },
- { value: "ADMIN", label: "ADMIN" }
+ { value: "ADMIN", label: "ADMIN" },
+ { value: "Remove Access", label: "Remove Access" }
];
- if (isAdmin) {
- accessOptionsWithRemove.push({
- value: "Remove Access",
- label: "Remove Access"
- });
- }
-
const selectedPrincipal = (e, input) => {
dispatch({
type: "SET_SELECTED_PRINCIPLE",
@@ -157,6 +152,10 @@ const PrinciplePermissionComp = ({
};
const addInSelectedPrincipal = (principle, input) => {
+ if (selectedAccess == undefined || selectedAccess.value == undefined) {
+ toast.error("Please select visibility!!");
+ return false;
+ }
for (let i = 0; i < principle.length; i++) {
let acl = { name: "", type: "", perm: "" };
acl.name = principle[i].value;
@@ -352,19 +351,19 @@ const PrinciplePermissionComp = ({
list[index]["perm"] = e.value;
setUserList(list);
setFilteredUserList(list);
- tempUserList = [...tempUserList, ...list];
+ tempUserList = list;
} else if (type == "GROUP") {
let list = groupOgList;
list[index]["perm"] = e.value;
setGroupList(list);
setFilteredGroupList(list);
- tempGroupList = [...tempGroupList, ...list];
+ tempGroupList = list;
} else if (type == "ROLE") {
let list = roleOgList;
list[index]["perm"] = e.value;
setRoleList(list);
setFilteredRoleList(list);
- tempRoleList = [...tempRoleList, ...list];
+ tempRoleList = list;
}
input.onChange(e);
}
@@ -436,13 +435,11 @@ const PrinciplePermissionComp = ({
userOgList;
if (
!selectedPrinciple ||
+ selectedPrinciple[0] == undefined ||
selectedPrinciple[0].value == undefined ||
selectedPrinciple.length === 0
) {
- toast.dismiss(toastId.current);
- toastId.current = toast.error(
- "Please select principal!!"
- );
+ toast.error("Please select principal!!");
return false;
}
addInSelectedPrincipal(selectedPrinciple, input);
@@ -575,7 +572,6 @@ const PrinciplePermissionComp = ({
{ label: obj.perm, value: obj.perm }
]}
isDisabled={isDetailView && !isAdmin}
- isClearable
/>
)}
/>
@@ -645,7 +641,6 @@ const PrinciplePermissionComp = ({
{ label: obj.perm, value: obj.perm }
]}
isDisabled={isDetailView && !isAdmin}
- isClearable
/>
)}
/>
@@ -714,7 +709,6 @@ const PrinciplePermissionComp = ({
defaultValue={[
{ label: obj.perm, value: obj.perm }
]}
- isClearable
/>
)}
/>
@@ -730,7 +724,11 @@ const PrinciplePermissionComp = ({
</Accordion>
</Card>
</div>
- <Modal show={showAddPrincipalModal} onHide={toggleAddPrincipalModal}>
+ <Modal
+ show={showAddPrincipalModal}
+ onHide={toggleAddPrincipalModal}
+ size="lg"
+ >
<Modal.Header closeButton>
<h3 className="gds-header bold">Add Principals</h3>
</Modal.Header>
@@ -741,41 +739,43 @@ const PrinciplePermissionComp = ({
render={({ input, meta }) => (
<div>
<Modal.Body>
- <AsyncSelect
- {...input}
- className="flex-1 gds-text-input"
- onChange={(e) => selectedPrincipal(e, input)}
- value={selectedPrinciple}
- filterOption={filterPrincipleOp}
- loadOptions={fetchPrincipleOp}
- components={{
- DropdownIndicator: () => null,
- IndicatorSeparator: () => null
- }}
- defaultOptions
- isMulti
- placeholder="Type to select Principals"
- data-name="usersSelect"
- data-cy="usersSelect"
- />
- <Field
- name="accessPermList"
- className="form-control"
- render={({ input }) => (
- <Select
- {...input}
- theme={serviceSelectTheme}
- styles={customStyles}
- options={accessOptions}
- onChange={(e) => setACL(e, input)}
- ref={selectVisibilityLevelRef}
- //value={selectedAccess}
- menuPlacement="auto"
- isClearable
- placeholder="Visibility Level"
- />
- )}
- />
+ <div className="d-flex gap-half">
+ <AsyncSelect
+ {...input}
+ className="flex-1 gds-text-input"
+ onChange={(e) => selectedPrincipal(e, input)}
+ value={selectedPrinciple}
+ filterOption={filterPrincipleOp}
+ loadOptions={fetchPrincipleOp}
+ components={{
+ DropdownIndicator: () => null,
+ IndicatorSeparator: () => null
+ }}
+ defaultOptions
+ isMulti
+ placeholder="Type to select Principals"
+ data-name="usersSelect"
+ data-cy="usersSelect"
+ />
+ <Field
+ name="accessPermList"
+ className="form-control"
+ render={({ input }) => (
+ <Select
+ {...input}
+ theme={serviceSelectTheme}
+ styles={customStyles}
+ options={accessOptions}
+ onChange={(e) => setACL(e, input)}
+ ref={selectVisibilityLevelRef}
+ //value={selectedAccess}
+ menuPlacement="auto"
+ isClearable
+ placeholder="Visibility Level"
+ />
+ )}
+ />
+ </div>
</Modal.Body>
<Modal.Footer>
<Button
@@ -792,6 +792,7 @@ const PrinciplePermissionComp = ({
userOgList;
if (
!selectedPrinciple ||
+ selectedPrinciple[0] == undefined ||
selectedPrinciple[0].value == undefined ||
selectedPrinciple.length === 0
) {
diff --git
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddDatashareView.jsx
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddDatashareView.jsx
index 64819b502..30be71988 100755
---
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddDatashareView.jsx
+++
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddDatashareView.jsx
@@ -21,7 +21,7 @@ import React, { useState, useReducer } from "react";
import { useNavigate } from "react-router-dom";
import { Button, Form as FormB, Card } from "react-bootstrap";
import Select from "react-select";
-import { groupBy } from "lodash";
+import { groupBy, filter } from "lodash";
import AsyncSelect from "react-select/async";
import { Form, Field } from "react-final-form";
import { fetchApi } from "Utils/fetchAPI";
@@ -281,7 +281,7 @@ const AddDatashareView = () => {
params: params
});
}
- op = serviceResp.data;
+ op = filter(serviceResp.data, ["isTagService", false]);
return op.map((obj) => ({
label: obj.name,
id: obj.id,
@@ -325,7 +325,8 @@ const AddDatashareView = () => {
skipNavigate: true
});
}
- return serviceResp.data.map(({ name, id, type }) => ({
+ let data = filter(serviceResp.data, ["isTagService", false]);
+ return data.map(({ name, id, type }) => ({
label: name,
id: id,
def: type
@@ -632,12 +633,18 @@ const AddDatashareView = () => {
onFocus={() => {
onFocusServiceSelect();
}}
+ components={{
+ DropdownIndicator: () => null,
+ IndicatorSeparator: () => null
+ }}
value={selectedService}
loadOptions={filterServiceByName}
onChange={(e) => onServiceChange(e, input)}
isClearable={true}
placeholder="Select Service"
width="500px"
+ data-name="serviceSelect"
+ data-cy="serviceSelect"
/>
</div>
)}
diff --git
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddSharedResourceComp.jsx
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddSharedResourceComp.jsx
index 8d4a1b7d9..ecb14c7b2 100755
---
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddSharedResourceComp.jsx
+++
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/AddSharedResourceComp.jsx
@@ -37,6 +37,7 @@ import { groupBy, isArray, maxBy, find } from "lodash";
import { toast } from "react-toastify";
import moment from "moment-timezone";
import { getServiceDef } from "../../../utils/appState";
+import { capitalizeFirstLetter } from "../../../utils/XAUtils";
const AddSharedResourceComp = ({
datashareId,
@@ -118,7 +119,7 @@ const AddSharedResourceComp = ({
}
if (obj?.accessTypes != undefined) {
data.permission = obj.accessTypes.map((item) => ({
- label: item,
+ label: capitalizeFirstLetter(item),
value: item
}));
}
diff --git
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/DatashareDetailLayout.jsx
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/DatashareDetailLayout.jsx
index adbeca360..57630ea5c 100755
---
a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/DatashareDetailLayout.jsx
+++
b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Datashare/DatashareDetailLayout.jsx
@@ -49,20 +49,25 @@ import dateFormat from "dateformat";
import { toast } from "react-toastify";
import { BlockUi } from "../../../components/CommonComponents";
import PrinciplePermissionComp from "../Dataset/PrinciplePermissionComp";
-import { Form } from "react-final-form";
+import { Form, Field } from "react-final-form";
import arrayMutators from "final-form-arrays";
import ReactPaginate from "react-paginate";
import AddSharedResourceComp from "./AddSharedResourceComp";
import CustomBreadcrumb from "../../CustomBreadcrumb";
+import PolicyConditionsComp from "../../PolicyListing/PolicyConditionsComp";
import {
isSystemAdmin,
parseSearchFilter,
- serverError
+ serverError,
+ policyConditionUpdatedJSON,
+ capitalizeFirstLetter
} from "../../../utils/XAUtils";
import XATableLayout from "../../../components/XATableLayout";
import moment from "moment-timezone";
import { getServiceDef } from "../../../utils/appState";
import DatashareInDatasetListComp from "../Dataset/DatashareInDatasetListComp";
+import { isEmpty, isObject, isEqual } from "lodash";
+import Select from "react-select";
const DatashareDetailLayout = () => {
let { datashareId } = useParams();
@@ -72,6 +77,7 @@ const DatashareDetailLayout = () => {
const [activeKey, setActiveKey] = useState("overview");
const [datashareInfo, setDatashareInfo] = useState({});
const [datashareDescription, setDatashareDescription] = useState();
+ const [datashareConditionExpr, setDatashareConditionExpr] = useState();
const [datashareTerms, setDatashareTerms] = useState();
const [loader, setLoader] = useState(true);
const [resourceContentLoader, setResourceContentLoader] = useState(false);
@@ -113,6 +119,7 @@ const DatashareDetailLayout = () => {
const [resourceSearchFilterParams, setResourceSearchFilterParams] = useState(
[]
);
+ const [showModal, policyConditionState] = useState(false);
const fetchIdRef = useRef(0);
const [searchFilterParams, setSearchFilterParams] = useState([]);
const [sharedResourceListData, setSharedResourceListData] = useState([]);
@@ -144,26 +151,54 @@ const DatashareDetailLayout = () => {
ACTIVE: 0,
DENIED: 0
});
+ const [accessTypeOptions, setAccessTypeOptions] = useState([]);
+ const [accessType, setAccessType] = useState([]);
useEffect(() => {
fetchDatashareInfo(datashareId);
}, []);
- const fetchShareStatusMetrics = async () => {
+ const fetchShareStatusMetrics = async (requestSearchFilterOptions) => {
try {
setLoader(true);
- let params = {};
+ let requestList = [];
+ let params =
+ requestSearchFilterParams != undefined
+ ? { ...requestSearchFilterOptions }
+ : {};
+ params["pageSize"] = 999999999;
params["dataShareId"] = datashareId;
- const resp = await fetchApi({
- url: `gds/datashare/summary`,
- params: params
- });
- let datasetReqList = resp.data.list[0].datasets;
+ try {
+ let resp = await fetchApi({
+ url: "gds/dataset/summary",
+ params: params
+ });
+ if (resp.data.list.length > 0) {
+ requestList = resp.data.list;
+ requestList?.forEach((dataset) => {
+ for (let i = 0; i < dataset.dataShares.length; i++) {
+ if (dataset.dataShares[i].dataShareId == datashareId) {
+ dataset.shareStatus = dataset.dataShares[i].shareStatus;
+ dataset.requestId = dataset.dataShares[i].id;
+ dataset.dataShareName = dataset.dataShares[i].dataShareName;
+ dataset.approver = dataset.dataShares[i].approver;
+ break;
+ }
+ }
+ });
+ }
+ } catch (error) {
+ serverError(error);
+ console.error(
+ `Error occurred while fetching Dataset request list! ${error}`
+ );
+ }
+
let activeCount = 0;
let requestedCount = 0;
let grantedCount = 0;
let deniedCount = 0;
- datasetReqList.forEach((request) => {
+ requestList.forEach((request) => {
switch (request.shareStatus) {
case "REQUESTED":
requestedCount += 1;
@@ -180,7 +215,7 @@ const DatashareDetailLayout = () => {
}
});
setShareStatusMetrics({
- totalCount: datasetReqList.length,
+ totalCount: requestList.length,
REQUESTED: requestedCount,
GRANTED: grantedCount,
ACTIVE: activeCount,
@@ -194,6 +229,11 @@ const DatashareDetailLayout = () => {
setLoader(false);
};
+ const onAccessTypeChange = (event, input) => {
+ setAccessType(event);
+ input.onChange(event);
+ };
+
const handleTabSelect = (key) => {
if (saveCancelButtons == true) {
setShowConfirmModal(true);
@@ -206,6 +246,18 @@ const DatashareDetailLayout = () => {
}
};
+ const DSpolicyConditions = [
+ {
+ itemId: 1,
+ name: "expression",
+ evaluator:
+
"org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator",
+ evaluatorOptions: { engineName: "JavaScript", "ui.isMultiline": "true" },
+ label: "Enter boolean expression",
+ description: "Boolean expression"
+ }
+ ];
+
const fetchDatashareInfo = async (datashareId) => {
let datashareResp = {};
let serviceResp = [];
@@ -219,15 +271,32 @@ const DatashareDetailLayout = () => {
});
const serviceDefs = getServiceDef();
let serviceDef = serviceDefs?.allServiceDefs?.find((servicedef) => {
- return servicedef.name == serviceResp.type;
+ return servicedef.name == serviceResp.data.type;
});
setServiceDef(serviceDef);
+ setAccessTypeOptions(
+ serviceDef.accessTypes.map(({ label, name: value }) => ({
+ label,
+ value
+ }))
+ );
} catch (error) {
setLoader(false);
console.error(
`Error occurred while fetching datashare details ! ${error}`
);
}
+ if (datashareResp.data.conditionExpr !== undefined) {
+ datashareResp.data.conditions = {
+ expression: datashareResp.data.conditionExpr
+ };
+ }
+ setAccessType(
+ datashareResp.data.defaultAccessTypes?.map((item) => ({
+ label: capitalizeFirstLetter(item),
+ value: item
+ }))
+ );
setDatashareName(datashareResp.data.name);
setService(serviceResp.data);
setDatashareInfo(datashareResp.data);
@@ -431,6 +500,12 @@ const DatashareDetailLayout = () => {
datashareInfo.name = datashareName;
datashareInfo.description = datashareDescription;
datashareInfo.termsOfUse = datashareTerms;
+ datashareInfo.conditionExpr = datashareConditionExpr;
+ datashareInfo.defaultAccessTypes = [];
+
+ accessType?.forEach((access) =>
+ datashareInfo.defaultAccessTypes.push(access.value)
+ );
datashareInfo.acl = { users: {}, groups: {}, roles: {} };
@@ -454,12 +529,12 @@ const DatashareDetailLayout = () => {
data: datashareInfo
});
toast.success("Datashare updated successfully!!");
- isDatashareNameEditable(false);
- showSaveCancelButton(false);
} catch (error) {
serverError(error);
console.error(`Error occurred while updating datashare ${error}`);
}
+ isDatashareNameEditable(false);
+ showSaveCancelButton(false);
setBlockUI(false);
setShowConfirmModal(false);
};
@@ -611,7 +686,7 @@ const DatashareDetailLayout = () => {
requestSearchFilterOptions
);
setRequestSearchFilterParams(searchFilterParam);
- //fetchDatashareRequestList(searchFilterParam, 0, false);
+ fetchShareStatusMetrics(searchFilterParam);
};
const fetchSharedResourcetList = useCallback(
@@ -723,7 +798,7 @@ const DatashareDetailLayout = () => {
title={accessObj}
key={accessObj}
>
- {accessObj}
+ {capitalizeFirstLetter(accessObj)}
</span>
))}
</div>
@@ -738,7 +813,6 @@ const DatashareDetailLayout = () => {
Cell: ({ row: { original } }) => {
return (
<div>
- {console.log(serviceDef, "table")}
{(isSystemAdmin() || userAclPerm == "ADMIN") && (
<div className="d-flex gap-half align-items-start">
{(isSystemAdmin() || userAclPerm == "ADMIN") && (
@@ -798,6 +872,26 @@ const DatashareDetailLayout = () => {
setRequestActiveKey(key);
};
+ const FormChange = (props) => {
+ const { isDirtyField, formValues } = props;
+ if (isDirtyField) {
+ setDatashareConditionExpr(props.formValues.conditions?.expression);
+ showSaveCancelButton(true);
+ }
+ return null;
+ };
+
+ const isDirtyFieldCheck = (values, initialValues) => {
+ let modifiedVal = false;
+ if (
+ !isEqual(values?.conditions, initialValues?.conditions) ||
+ !isEqual(values?.defaultAccessTypes, initialValues?.defaultAccessTypes)
+ ) {
+ modifiedVal = true;
+ }
+ return modifiedVal;
+ };
+
return (
<>
<Form
@@ -805,7 +899,8 @@ const DatashareDetailLayout = () => {
mutators={{
...arrayMutators
}}
- render={({}) => (
+ initialValues={datashareInfo}
+ render={({ values, dirty, initialValues }) => (
<React.Fragment>
<div
className={
@@ -878,37 +973,36 @@ const DatashareDetailLayout = () => {
<span className="pipe" />
</>
)}
- {!datashareNameEditable ||
- ((isSystemAdmin() ||
- userAclPerm == "ADMIN" ||
- userAclPerm == "POLICY_ADMIN") && (
- <div>
- {saveCancelButtons ? (
- <div className="gds-header-btn-grp">
- <Button
- variant="secondary"
- size="sm"
- onClick={() => removeChanges()}
- data-id="cancel"
- data-cy="cancel"
- >
- Cancel
- </Button>
- <Button
- variant="primary"
- onClick={updateDatashareDetails}
- size="sm"
- data-id="save"
- data-cy="save"
- >
- Save
- </Button>
- </div>
- ) : (
- <p></p>
- )}
- </div>
- ))}
+ {(isSystemAdmin() ||
+ userAclPerm == "ADMIN" ||
+ userAclPerm == "POLICY_ADMIN") && (
+ <div>
+ {saveCancelButtons ? (
+ <div className="gds-header-btn-grp">
+ <Button
+ variant="secondary"
+ size="sm"
+ onClick={() => removeChanges()}
+ data-id="cancel"
+ data-cy="cancel"
+ >
+ Cancel
+ </Button>
+ <Button
+ variant="primary"
+ onClick={updateDatashareDetails}
+ size="sm"
+ data-id="save"
+ data-cy="save"
+ >
+ Save
+ </Button>
+ </div>
+ ) : (
+ <p></p>
+ )}
+ </div>
+ )}
{!datashareNameEditable && !saveCancelButtons && (
<div>
@@ -976,6 +1070,14 @@ const DatashareDetailLayout = () => {
<Tab eventKey="overview" title="OVERVIEW">
{activeKey == "overview" ? (
<div>
+ <FormChange
+ isDirtyField={
+ dirty == true || !isEqual(initialValues, values)
+ ? isDirtyFieldCheck(values, initialValues)
+ : false
+ }
+ formValues={values}
+ />
<div className="gds-tab-content gds-content-border
px-3">
<div className="gds-inline-field-grp">
<div className="wrapper">
@@ -1045,6 +1147,133 @@ const DatashareDetailLayout = () => {
</div>
</div>
</div>
+
+ <div className="gds-action-card mb-5 gds-tab-content
gds-content-border px-3">
+ <div
+ className={
+ values.conditions == undefined
+ ? "gds-section-title border-0 p-0"
+ : "gds-section-title"
+ }
+ >
+ <p className="gds-card-heading">
+ Default Condition
+ </p>
+ {isSystemAdmin() || userAclPerm == "ADMIN" ? (
+ <Button
+ className="btn btn-sm"
+ onClick={() => {
+ policyConditionState(true);
+ }}
+ data-js="customPolicyConditions"
+ data-cy="customPolicyConditions"
+ variant="secondary"
+ >
+ {values.conditions !== undefined
+ ? "Modify Condition"
+ : "Set Condition"}
+ </Button>
+ ) : (
+ <></>
+ )}
+ </div>
+ {values.conditions !== undefined &&
+ Object.keys(values.conditions).map((keyName) => {
+ if (
+ values.conditions[keyName] != "" &&
+ values.conditions[keyName] != null
+ ) {
+ let conditionObj = find(
+ DSpolicyConditions,
+ function (m) {
+ if (m.name == keyName) {
+ return m;
+ }
+ }
+ );
+ return (
+ <div className="pt-3">
+ {isObject(values.conditions[keyName]) ? (
+ <div>
+ <span className="fnt-14">
+ {values.conditions[keyName].length
>
+ 1
+ ? values.conditions[keyName].map(
+ (m) => {
+ return ` ${m.label} `;
+ }
+ )
+ : values.conditions[keyName]
+ .label}
+ </span>
+ </div>
+ ) : (
+ <div>
+ <span className="fnt-14">
+ {values.conditions[keyName]}
+ </span>
+ </div>
+ )}
+ </div>
+ );
+ }
+ })}
+ </div>
+
+ {showModal && (
+ <Field
+ className="form-control"
+ name="conditions"
+ render={({ input }) => (
+ <PolicyConditionsComp
+
policyConditionDetails={policyConditionUpdatedJSON(
+ DSpolicyConditions
+ )}
+ inputVal={input}
+ showModal={showModal}
+ handleCloseModal={policyConditionState}
+ />
+ )}
+ />
+ )}
+
+ <div className="gds-action-card mb-5 gds-tab-content
gds-content-border px-3">
+ <div className="gds-section-title">
+ <p className="gds-card-heading">
+ Default access types:
+ </p>
+ </div>
+ <div className="gds-flex mg-b-10 mg-t-20">
+ <div className="w-100">
+ <Field
+ name={`defaultAccessTypes`}
+ render={({ input, meta }) => (
+ <div>
+ <Select
+ {...input}
+ className="w-100"
+ options={accessTypeOptions}
+ onChange={(e) =>
+ onAccessTypeChange(e, input)
+ }
+ menuPortalTarget={document.body}
+ value={accessType}
+ isDisabled={
+ !isSystemAdmin() &&
+ userAclPerm != "ADMIN"
+ }
+ menuPlacement="auto"
+ placeholder="All Permissions"
+ isClearable
+ isMulti
+ />
+ </div>
+ )}
+ />
+ </div>
+ </div>
+ </div>
+
{(isSystemAdmin() || userAclPerm != "VIEW") && (
<PrinciplePermissionComp
userList={userList}