blob: 1fef5501bb1a96529508bc778abc26047bc7fa71 [file] [log] [blame]
/*
* 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 } from "react";
import { Form as FormB, Modal, Button, Table, Badge } from "react-bootstrap";
import { Form, Field } from "react-final-form";
import Select from "react-select";
import arrayMutators from "final-form-arrays";
import { FieldArray } from "react-final-form-arrays";
import {
groupBy,
keys,
indexOf,
findIndex,
isEmpty,
includes,
difference,
map,
every,
cloneDeep
} from "lodash";
import { RangerPolicyType } from "Utils/XAEnums";
import { getServiceDef } from "../../utils/appState";
export default function TagBasePermissionItem(props) {
const serviceDefs = cloneDeep(getServiceDef());
const {
options,
inputVal,
formValues,
serviceCompDetails,
dataMaskIndex,
attrName
} = props;
const [showTagPermissionItem, tagPermissionItem] = useState(false);
const msgStyles = {
background: "white",
color: "black"
};
const noOptionMsg = (inputValue) => {
if (
formValues?.policyType ==
RangerPolicyType.RANGER_MASKING_POLICY_TYPE.value
) {
if (!inputValue) {
return " You can only select 1 item";
} else {
return "No results found";
}
} else {
return "No Options";
}
};
const tagServicePerms = groupBy(options, function (obj) {
let val = obj.value;
return val.substr(0, val.indexOf(":"));
});
const handleSubmit = (values) => {
let tagPermissionType = values;
delete tagPermissionType.servicesDefType;
if (values?.tableList) {
tagPermissionType.tableList = values.tableList.filter((m) => {
if (m.permission) {
if (!isEmpty(m.permission)) {
return m;
} else {
m.serviceName = "";
if (
serviceCompDetails?.name == "tag" &&
formValues?.policyType ==
RangerPolicyType.RANGER_MASKING_POLICY_TYPE.value &&
formValues?.dataMaskPolicyItems[dataMaskIndex]?.dataMaskInfo
) {
formValues.dataMaskPolicyItems[dataMaskIndex].dataMaskInfo = {};
}
}
}
});
}
inputVal.onChange(tagPermissionType);
handleClose();
};
const handleClose = () => {
tagPermissionItem(false);
};
const serviceOnChange = (e, input, values, push, remove) => {
if (e.action == "select-option") {
push("tableList", {
serviceName: e.option.value
});
} else {
let removeItemIndex = findIndex(input.value, [
"value",
e?.removedValue?.value
]);
remove("tableList", removeItemIndex);
if (
serviceCompDetails?.name == "tag" &&
formValues?.policyType ==
RangerPolicyType.RANGER_MASKING_POLICY_TYPE.value &&
formValues?.dataMaskPolicyItems[dataMaskIndex]?.dataMaskInfo
) {
formValues.dataMaskPolicyItems[dataMaskIndex].dataMaskInfo = {};
}
}
input.onChange(values);
};
const selectOptions = (values) => {
if (
formValues?.policyType ==
RangerPolicyType.RANGER_MASKING_POLICY_TYPE.value
) {
if (values?.tableList?.length > 0) {
return [];
} else {
return keys(tagServicePerms).map((m) => ({
value: m,
label: m.toUpperCase()
}));
}
} else {
if (attrName === "policyItems") {
return map(keys(tagServicePerms), (m) => ({
value: m,
label: m.toUpperCase()
}));
} else {
let enableDenyAndExceptions = [];
let filterAccessOptions = [];
enableDenyAndExceptions = serviceCompDetails?.accessTypes?.filter(
(access) => {
if (
includes(
serviceDefs?.allServiceDefs
?.map((servicedef) => {
if (
servicedef?.options?.enableDenyAndExceptionsInPolicies ==
"false"
) {
return servicedef.name;
}
})
.filter(Boolean),
access.name.substr(0, access.name.indexOf(":"))
)
) {
return access;
}
}
);
filterAccessOptions = groupBy(enableDenyAndExceptions, function (obj) {
let val = obj.name;
return val.substr(0, val.indexOf(":"));
});
return difference(
keys(tagServicePerms),
keys(filterAccessOptions)
)?.map((m) => ({
value: m,
label: m.toUpperCase()
}));
}
}
};
const isChecked = (obj, input) => {
let selectedVal = input.value || [];
return indexOf(selectedVal, obj) !== -1;
};
const isAllChecked = (fieldObj, objVal) => {
return (
!!fieldObj?.permission &&
fieldObj?.permission?.length > 0 &&
fieldObj?.permission?.length === objVal?.length
);
};
const isSelectAllChecked = (values) => {
let fieldValues = !isEmpty(values) ? [...values] : [];
return !isEmpty(fieldValues)
? every(fieldValues, (p) => {
return p?.permission?.length == tagServicePerms[p.serviceName].length;
})
: false;
};
const handleChange = (e, value, input) => {
let val = [...input.value] || [];
if (e.target.checked) {
val.push(value);
} else {
let index = indexOf(val, value);
val.splice(index, 1);
}
input.onChange(val);
};
const handleSelectAllChange = (e, index, fields) => {
let fieldVal = { ...fields.value[index] };
let val = [];
if (e.target.checked) {
val = tagServicePerms[fieldVal.serviceName].map(({ value }) => value);
}
fieldVal.permission = val;
fields.update(index, fieldVal);
};
const selectAllPermissions = (e, values, form) => {
const { checked } = e.target;
const fieldValues = cloneDeep(values?.tableList);
if (!isEmpty(fieldValues)) {
fieldValues.filter((p) => {
let val = [];
val = tagServicePerms[p.serviceName].map(({ value }) => value);
p.permission = checked ? val : [];
});
form.batch(() => {
form.change("selectAll", checked);
form.change("tableList", fieldValues);
});
}
};
const formInitialData = () => {
let formData = {};
if (inputVal?.value?.tableList?.length > 0) {
formData.servicesDefType = inputVal.value.tableList.map((m) => {
return {
label: m.serviceName.toUpperCase(),
value: m.serviceName
};
});
formData.tableList = inputVal.value.tableList;
}
return formData;
};
const tagAccessTypeDisplayVal = (val) => {
return val.map((m, index) => {
return (
<h6 className="d-inline mr-1 mb-1" key={index}>
<Badge variant="info">{m.serviceName.toUpperCase()}</Badge>
</h6>
);
});
};
return (
<>
<div
className="editable"
onClick={() => {
tagPermissionItem(true);
}}
>
{inputVal?.value?.tableList?.length > 0 ? (
<div className="text-center">
<div className="editable-edit-text">
{tagAccessTypeDisplayVal(inputVal?.value?.tableList)}
</div>
<Button
className="mg-10 mx-auto d-block btn-mini"
size="sm"
variant="outline-dark"
onClick={(e) => {
e.stopPropagation();
tagPermissionItem(true);
}}
>
<i className="fa-fw fa fa-pencil"></i>
</Button>
</div>
) : (
<div className="text-center">
<span className="editable-add-text">Add Permissions</span>
<div>
<Button
size="sm"
className="mg-10 mx-auto d-block btn-mini"
variant="outline-dark"
onClick={(e) => {
e.stopPropagation();
tagPermissionItem(true);
}}
>
<i className="fa-fw fa fa-plus"></i>
</Button>
</div>
</div>
)}
</div>
<Modal
show={showTagPermissionItem}
onHide={handleClose}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Form
onSubmit={handleSubmit}
initialValues={formInitialData()}
mutators={{
...arrayMutators
}}
render={({
handleSubmit,
form: {
mutators: { push, remove }
},
form,
values
}) => (
<form onSubmit={handleSubmit}>
<Modal.Header closeButton>
<Modal.Title>Components Permissions</Modal.Title>
</Modal.Header>
<Modal.Body>
<Field
name="servicesDefType"
render={({ input }) => (
<FormB.Group className="mb-3">
<b>Select Component:</b>
<Select
{...input}
onChange={(values, e) =>
serviceOnChange(e, input, values, push, remove)
}
isMulti
options={selectOptions(values)}
noOptionsMessage={({ inputValue }) =>
noOptionMsg(inputValue)
}
styles={{
noOptionsMessage: (base) => ({
...base,
...msgStyles
})
}}
components={{
DropdownIndicator: () => null,
IndicatorSeparator: () => null
}}
isClearable={false}
isSearchable={true}
placeholder="Select Service Name"
/>
</FormB.Group>
)}
/>
<Table striped bordered>
<thead>
<tr>
<th className="bg-white text-dark align-middle">
<FormB.Group className="d-flex align-items-center mb-0">
<Field
name="selectAll"
type="checkbox"
render={({ input }) => (
<>
<input
{...input}
className="mr-1"
checked={isSelectAllChecked(
values?.tableList
)}
onChange={(e) => {
selectAllPermissions(e, values, form);
}}
/>
Component
</>
)}
/>
</FormB.Group>
</th>
<th className="bg-white text-dark align-middle">
Permission
</th>
</tr>
</thead>
<tbody>
<FieldArray name="tableList">
{({ fields }) =>
fields.map((name, index) => (
<tr className="bg-white" key={index}>
<td className="align-middle td-padding-modal">
<h6>
<FormB.Group className="d-inline">
<FormB.Check
inline
key={fields.value[
index
].serviceName.toUpperCase()}
checked={isAllChecked(
fields.value[index],
tagServicePerms[
fields.value[index].serviceName
]
)}
type="checkbox"
label={fields.value[
index
].serviceName.toUpperCase()}
onChange={(e) =>
handleSelectAllChange(e, index, fields)
}
/>
</FormB.Group>
</h6>
</td>
<td className="align-middle">
<Field
className="form-control"
name={`${name}.permission`}
render={({ input }) => (
<div>
{tagServicePerms[
fields.value[index].serviceName
].map((obj) => (
<h6 className="d-inline" key={obj.value}>
<FormB.Group
className="d-inline"
controlId={obj.value}
>
<FormB.Check
inline
checked={isChecked(
obj.value,
input
)}
type="checkbox"
label={obj.label}
onChange={(e) =>
handleChange(e, obj.value, input)
}
/>
</FormB.Group>
</h6>
))}
</div>
)}
/>
</td>
</tr>
))
}
</FieldArray>
</tbody>
</Table>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" size="sm" onClick={handleClose}>
Close
</Button>
<Button title="Save" size="sm" type="submit">
Save
</Button>
</Modal.Footer>
</form>
)}
/>
</Modal>
</>
);
}