| /* |
| * 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,Row |
| * 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, useReducer, useRef } from "react"; |
| import userGreyIcon from "../../../images/user-grey.svg"; |
| import groupGreyIcon from "../../../images/group-grey.svg"; |
| import roleGreyIcon from "../../../images/role-grey.svg"; |
| import userColourIcon from "../../../images/user-colour.svg"; |
| import groupColourIcon from "../../../images/group-colour.svg"; |
| import roleColourIcon from "../../../images/role-colour.svg"; |
| import { Accordion, Card, Button, Modal } from "react-bootstrap"; |
| import { Field } from "react-final-form"; |
| import Select from "react-select"; |
| 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: [] |
| }; |
| |
| const principleFormReducer = (state, action) => { |
| switch (action.type) { |
| case "SET_SELECTED_PRINCIPLE": |
| return { |
| ...state, |
| selectedPrinciple: action.selectedPrinciple |
| }; |
| default: |
| throw new Error(); |
| } |
| }; |
| |
| const PrinciplePermissionComp = ({ |
| userList, |
| groupList, |
| roleList, |
| isAdmin, |
| type, |
| onDataChange, |
| isDetailView |
| }) => { |
| const [userOgList, setUserList] = useState(userList); |
| const [groupOgList, setGroupList] = useState(groupList); |
| const [roleOgList, setRoleList] = useState(roleList); |
| const [filteredUserList, setFilteredUserList] = useState(userList); |
| const [filteredGroupList, setFilteredGroupList] = useState(groupList); |
| const [filteredRoleList, setFilteredRoleList] = useState(roleList); |
| const [selectedACLFilter, setSelectedACLFilter] = useState({}); |
| const [searchPrinciple, setSearchPrinciple] = useState(); |
| const [userAccordion, setUserAccordion] = useState(false); |
| const [groupAccordion, setGroupAccordion] = useState(false); |
| const [roleAccordion, setRoleAccordion] = useState(false); |
| const [principleDetails, dispatch] = useReducer( |
| principleFormReducer, |
| initialState |
| ); |
| const { selectedPrinciple } = principleDetails; |
| const selectVisibilityLevelRef = useRef(null); |
| const [selectedAccess, setSelectedAccess] = useState({}); |
| const [showAddPrincipalModal, setShowAddPrincipalModal] = useState(false); |
| |
| const accessOptions = [ |
| { value: "LIST", label: "LIST" }, |
| { value: "VIEW", label: "VIEW" }, |
| { value: "AUDIT", label: "AUDIT" }, |
| { value: "POLICY_ADMIN", label: "POLICY_ADMIN" }, |
| { value: "ADMIN", label: "ADMIN" } |
| ]; |
| |
| const accessOptionsWithRemove = [ |
| { value: "LIST", label: "LIST" }, |
| { value: "VIEW", label: "VIEW" }, |
| { value: "AUDIT", label: "AUDIT" }, |
| { value: "POLICY_ADMIN", label: "POLICY_ADMIN" }, |
| { value: "ADMIN", label: "ADMIN" }, |
| { value: "Remove Access", label: "Remove Access" } |
| ]; |
| |
| const selectedPrincipal = (e, input) => { |
| dispatch({ |
| type: "SET_SELECTED_PRINCIPLE", |
| selectedPrinciple: e |
| }); |
| input.onChange(e); |
| }; |
| |
| const filterPrincipleOp = ({ data }) => { |
| let list = []; |
| |
| if (data["type"] == "USER") { |
| list = userOgList; |
| } else if (data["type"] == "GROUP") { |
| list = groupOgList; |
| } else if (data["type"] == "ROLE") { |
| list = roleOgList; |
| } |
| return findIndex(list, { name: data.value }) === -1; |
| }; |
| |
| const fetchPrincipleOp = async (inputValue) => { |
| let params = { name: inputValue || "" }; |
| let data = []; |
| const principalResp = await fetchApi({ |
| url: "xusers/lookup/principals", |
| params: params |
| }); |
| data = principalResp.data; |
| return data.map((obj) => ({ |
| label: ( |
| <div> |
| <img |
| src={ |
| obj.type == "USER" |
| ? userGreyIcon |
| : obj.type == "GROUP" |
| ? groupGreyIcon |
| : roleGreyIcon |
| } |
| height="20px" |
| width="20px" |
| />{" "} |
| {obj.name}{" "} |
| </div> |
| ), |
| value: obj.name, |
| type: obj.type |
| })); |
| }; |
| |
| const setACL = (e, input) => { |
| setSelectedAccess(e); |
| input.onChange(e); |
| }; |
| |
| 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; |
| acl.perm = selectedAccess.value; |
| acl.type = principle[i].type; |
| principle[i] = acl; |
| } |
| |
| let tempUserList = userOgList; |
| let tempGroupList = groupOgList; |
| let tempRoleList = roleOgList; |
| let principleGroupBy = _.groupBy(principle, "type"); |
| if (principleGroupBy["USER"] != undefined) { |
| principleGroupBy["USER"].forEach((obj) => { |
| tempUserList.push(obj); |
| }); |
| setUserList(tempUserList); |
| setFilteredUserList(tempUserList); |
| console.log("userOglist PP"); |
| console.log(userOgList); |
| } |
| |
| if (principleGroupBy["GROUP"] != undefined) { |
| principleGroupBy["GROUP"].forEach((obj) => { |
| tempGroupList.push(obj); |
| }); |
| setGroupList(tempGroupList); |
| setFilteredGroupList(tempGroupList); |
| } |
| |
| if (principleGroupBy["ROLE"] != undefined) { |
| principleGroupBy["ROLE"].forEach((obj) => { |
| tempRoleList.push(obj); |
| }); |
| setRoleList(tempRoleList); |
| setFilteredRoleList(tempRoleList); |
| } |
| |
| onDataChange(tempUserList, tempGroupList, tempRoleList); |
| //setSelectedAccess({ value: "LIST", label: "LIST" }); |
| |
| dispatch({ |
| type: "SET_SELECTED_PRINCIPLE", |
| selectedPrinciple: [] |
| }); |
| if (selectVisibilityLevelRef.current) { |
| selectVisibilityLevelRef.current.clearValue(); |
| } |
| }; |
| |
| const changeUserAccordion = () => { |
| setUserAccordion(!userAccordion); |
| }; |
| |
| const changeGroupAccordion = () => { |
| setGroupAccordion(!groupAccordion); |
| }; |
| |
| const changeRoleAccordion = () => { |
| setRoleAccordion(!roleAccordion); |
| }; |
| |
| const serviceSelectTheme = (theme) => { |
| return { |
| ...theme, |
| colors: { |
| ...theme.colors, |
| primary: "#0081ab" |
| } |
| }; |
| }; |
| |
| const customStyles = { |
| control: (provided) => ({ |
| ...provided, |
| maxHeight: "40px", |
| width: "172px" |
| }), |
| indicatorsContainer: (provided) => ({ |
| ...provided |
| }) |
| }; |
| |
| const onChangePrincipleName = (event) => { |
| setSearchPrinciple(event.target.value); |
| filterPrincipleList( |
| event.target.value.length > 0 ? event.target.value : undefined, |
| true, |
| undefined, |
| false |
| ); |
| }; |
| |
| const onACLFilterChange = (e, input) => { |
| setSelectedACLFilter(e); |
| input.onChange(e); |
| filterPrincipleList( |
| undefined, |
| false, |
| e != undefined ? e.value : undefined, |
| true |
| ); |
| }; |
| |
| const filterPrincipleList = (name, nameChange, perm, permChange) => { |
| if (name === undefined && !nameChange) { |
| name = |
| searchPrinciple != undefined && searchPrinciple.length > 0 |
| ? searchPrinciple |
| : undefined; |
| } |
| |
| if (perm === undefined && !permChange) { |
| perm = |
| selectedACLFilter != undefined ? selectedACLFilter.value : undefined; |
| } |
| |
| setFilteredUserList( |
| userOgList.filter(function (user) { |
| if (name != undefined && perm != undefined) { |
| return user.name.startsWith(name, 0) && user.perm == perm; |
| } else if (name != undefined) { |
| return user.name.startsWith(name, 0); |
| } else if (perm != undefined) { |
| return user.perm == perm; |
| } else { |
| return true; |
| } |
| }) |
| ); |
| setFilteredGroupList( |
| groupOgList.filter(function (group) { |
| if (name != undefined && perm != undefined) { |
| return group.name.startsWith(name, 0) && group.perm == perm; |
| } else if (name != undefined) { |
| return group.name.startsWith(name, 0); |
| } else if (perm != undefined) { |
| return group.perm == perm; |
| } else { |
| return true; |
| } |
| }) |
| ); |
| setFilteredRoleList( |
| roleOgList.filter(function (role) { |
| if (name != undefined && perm != undefined) { |
| return role.name.startsWith(name, 0) && role.perm == perm; |
| } else if (name != undefined) { |
| return role.name.startsWith(name, 0); |
| } else if (perm != undefined) { |
| return role.perm == perm; |
| } else { |
| return true; |
| } |
| }) |
| ); |
| }; |
| |
| const handleTableSelectedValue = (e, input, index, name, type) => { |
| let tempUserList = userOgList; |
| let tempGroupList = groupOgList; |
| let tempRoleList = roleOgList; |
| if (e?.label == "Remove Access") { |
| if (type == "USER") { |
| let list = userOgList; |
| //list.splice(index, 1); |
| remove(userOgList, function (n) { |
| return n.name == name; |
| }); |
| setUserList(userOgList); |
| setFilteredUserList(userOgList); |
| tempUserList = [...tempUserList, ...userOgList]; |
| } else if (type == "GROUP") { |
| remove(groupOgList, function (n) { |
| return n.name == name; |
| }); |
| setGroupList(groupOgList); |
| setFilteredGroupList(groupOgList); |
| tempGroupList = [...tempGroupList, ...groupOgList]; |
| } else if (type == "ROLE") { |
| remove(roleOgList, function (n) { |
| return n.name == name; |
| }); |
| setRoleList(roleOgList); |
| setFilteredRoleList(roleOgList); |
| tempRoleList = [...tempRoleList, ...roleOgList]; |
| } |
| } else { |
| if (type == "USER") { |
| let list = userOgList; |
| console.log("----------"); |
| console.log(list[index]); |
| list[index]["perm"] = e.value; |
| setUserList(list); |
| setFilteredUserList(list); |
| tempUserList = list; |
| } else if (type == "GROUP") { |
| let list = groupOgList; |
| list[index]["perm"] = e.value; |
| setGroupList(list); |
| setFilteredGroupList(list); |
| tempGroupList = list; |
| } else if (type == "ROLE") { |
| let list = roleOgList; |
| list[index]["perm"] = e.value; |
| setRoleList(list); |
| setFilteredRoleList(list); |
| tempRoleList = list; |
| } |
| input.onChange(e); |
| } |
| onDataChange(tempUserList, tempGroupList, tempRoleList); |
| }; |
| |
| const openAddPrincipalModal = () => { |
| setShowAddPrincipalModal(true); |
| }; |
| |
| const toggleAddPrincipalModal = () => { |
| setShowAddPrincipalModal(false); |
| }; |
| |
| const containerStyle = { |
| display: "flex", |
| justifyContent: "space-between" |
| }; |
| |
| return ( |
| <div className="gds-tab-content"> |
| {!isDetailView && ( |
| <div className="gds-form-input"> |
| <Field |
| className="form-control" |
| name="selectedPrinciple" |
| render={({ input, meta }) => ( |
| <div className="gds-add-principle"> |
| {" "} |
| <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" |
| /> |
| )} |
| ></Field> |
| <Button |
| type="button" |
| className="btn btn-primary" |
| onClick={() => { |
| userOgList; |
| if ( |
| !selectedPrinciple || |
| selectedPrinciple[0] == undefined || |
| selectedPrinciple[0].value == undefined || |
| selectedPrinciple.length === 0 |
| ) { |
| toast.error("Please select principal!!"); |
| return false; |
| } |
| addInSelectedPrincipal(selectedPrinciple, input); |
| filterPrincipleList( |
| undefined, |
| undefined, |
| undefined, |
| undefined |
| ); |
| }} |
| size="md" |
| data-name="usersAddBtn" |
| data-cy="usersAddBtn" |
| > |
| Add Principals |
| </Button> |
| </div> |
| )} |
| /> |
| </div> |
| )} |
| |
| <div> |
| <Card className="gds-section-card gds-bg-white"> |
| <div className="gds-section-title"> |
| <p className="gds-card-heading" style={containerStyle}> |
| {type == "dataset" |
| ? "Dataset" |
| : type == "datashare" |
| ? "Datashare" |
| : ""}{" "} |
| Visibility |
| {isDetailView && isAdmin && ( |
| <Button |
| type="button" |
| className="btn btn-primary" |
| onClick={() => openAddPrincipalModal()} |
| size="md" |
| data-name="opnAddPrincipalModal" |
| data-cy="opnAddPrincipalModal" |
| > |
| Add Principals |
| </Button> |
| )} |
| </p> |
| </div> |
| <div className="gds-flex mg-b-10"> |
| <input |
| type="search" |
| className="form-control gds-input" |
| placeholder="Search..." |
| onChange={(e) => onChangePrincipleName(e)} |
| value={searchPrinciple} |
| /> |
| |
| <Field |
| name="accessPermFilter" |
| className="form-control" |
| render={({ input }) => ( |
| <Select |
| {...input} |
| theme={serviceSelectTheme} |
| styles={customStyles} |
| options={accessOptions} |
| onChange={(e) => onACLFilterChange(e, input)} |
| //value={selectedACLFilter} |
| menuPlacement="auto" |
| placeholder="Visibility Level" |
| isClearable |
| /> |
| )} |
| /> |
| </div> |
| |
| <Accordion className="mg-b-10" defaultActiveKey="0"> |
| <Card> |
| <div className="border-bottom"> |
| <Accordion.Toggle |
| as={Card.Header} |
| eventKey="1" |
| onClick={changeUserAccordion} |
| className="border-bottom-0 d-flex align-items-center justify-content-between gds-acc-card-header" |
| data-id="panel" |
| data-cy="panel" |
| > |
| <div className="d-flex align-items-center gap-half"> |
| <img src={userColourIcon} height="30px" width="30px" /> |
| Users ( |
| {filteredUserList == undefined |
| ? 0 |
| : filteredUserList.length} |
| ) |
| </div> |
| |
| {userAccordion ? ( |
| <i className="fa fa-angle-up fa-lg font-weight-bold"></i> |
| ) : ( |
| <i className="fa fa-angle-down fa-lg font-weight-bold"></i> |
| )} |
| </Accordion.Toggle> |
| </div> |
| <Accordion.Collapse eventKey="1"> |
| <Card.Body> |
| {filteredUserList != undefined && |
| filteredUserList.length > 0 ? ( |
| filteredUserList.map((obj, index) => { |
| return ( |
| <div className="gds-principle-listing" key={obj.name}> |
| <span title={obj.name}>{obj.name}</span> |
| |
| <Field |
| name="aclPerms" |
| render={({ input, meta }) => ( |
| <Select |
| // {...input.value} |
| theme={serviceSelectTheme} |
| options={accessOptionsWithRemove} |
| menuPortalTarget={document.body} |
| onChange={(e) => |
| handleTableSelectedValue( |
| e, |
| input, |
| index, |
| obj.name, |
| "USER" |
| ) |
| } |
| menuPlacement="auto" |
| defaultValue={[ |
| { label: obj.perm, value: obj.perm } |
| ]} |
| isDisabled={isDetailView && !isAdmin} |
| /> |
| )} |
| /> |
| </div> |
| ); |
| }) |
| ) : ( |
| <p className="mt-1">--</p> |
| )} |
| </Card.Body> |
| </Accordion.Collapse> |
| </Card> |
| </Accordion> |
| |
| <Accordion className="mg-b-10" defaultActiveKey="0"> |
| <Card> |
| <div className="border-bottom"> |
| <Accordion.Toggle |
| as={Card.Header} |
| eventKey="1" |
| onClick={changeGroupAccordion} |
| className="border-bottom-0 d-flex align-items-center justify-content-between gds-acc-card-header" |
| data-id="panel" |
| data-cy="panel" |
| > |
| <div className="d-flex align-items-center gap-half"> |
| <img src={groupColourIcon} height="30px" width="30px" /> |
| Groups ( |
| {filteredGroupList == undefined |
| ? 0 |
| : filteredGroupList.length} |
| ) |
| </div> |
| {groupAccordion ? ( |
| <i className="fa fa-angle-up fa-lg font-weight-bold"></i> |
| ) : ( |
| <i className="fa fa-angle-down fa-lg font-weight-bold"></i> |
| )} |
| </Accordion.Toggle> |
| </div> |
| <Accordion.Collapse eventKey="1"> |
| <Card.Body> |
| {filteredGroupList != undefined && |
| filteredGroupList.length > 0 ? ( |
| filteredGroupList.map((obj, index) => { |
| return ( |
| <div className="gds-principle-listing" key={obj.name}> |
| <span title={obj.name}>{obj.name}</span> |
| <Field |
| name="aclPerms" |
| render={({ input, meta }) => ( |
| <Select |
| theme={serviceSelectTheme} |
| options={accessOptionsWithRemove} |
| menuPortalTarget={document.body} |
| onChange={(e) => |
| handleTableSelectedValue( |
| e, |
| input, |
| index, |
| obj.name, |
| "GROUP" |
| ) |
| } |
| menuPlacement="auto" |
| defaultValue={[ |
| { label: obj.perm, value: obj.perm } |
| ]} |
| isDisabled={isDetailView && !isAdmin} |
| /> |
| )} |
| /> |
| </div> |
| ); |
| }) |
| ) : ( |
| <p className="mt-1">--</p> |
| )} |
| </Card.Body> |
| </Accordion.Collapse> |
| </Card> |
| </Accordion> |
| |
| <Accordion className="mg-b-10" defaultActiveKey="0"> |
| <Card> |
| <div className="border-bottom"> |
| <Accordion.Toggle |
| as={Card.Header} |
| eventKey="1" |
| onClick={changeRoleAccordion} |
| className="border-bottom-0 d-flex align-items-center justify-content-between gds-acc-card-header" |
| data-id="panel" |
| data-cy="panel" |
| > |
| <div className="d-flex align-items-center gap-half"> |
| <img src={roleColourIcon} height="30px" width="30px" /> |
| Roles ( |
| {filteredRoleList == undefined |
| ? 0 |
| : filteredRoleList.length} |
| ) |
| </div> |
| {roleAccordion ? ( |
| <i className="fa fa-angle-up fa-lg font-weight-bold"></i> |
| ) : ( |
| <i className="fa fa-angle-down fa-lg font-weight-bold"></i> |
| )} |
| </Accordion.Toggle> |
| </div> |
| <Accordion.Collapse eventKey="1"> |
| <Card.Body> |
| {filteredRoleList?.length > 0 ? ( |
| filteredRoleList.map((obj, index) => { |
| return ( |
| <div className="gds-principle-listing" key={obj.name}> |
| <span title={obj.name}>{obj.name}</span> |
| <Field |
| name="aclPerms" |
| render={({ input, meta }) => ( |
| <Select |
| theme={serviceSelectTheme} |
| options={accessOptionsWithRemove} |
| menuPortalTarget={document.body} |
| onChange={(e) => |
| handleTableSelectedValue( |
| e, |
| input, |
| index, |
| obj.name, |
| "ROLE" |
| ) |
| } |
| isDisabled={isDetailView && !isAdmin} |
| menuPlacement="auto" |
| defaultValue={[ |
| { label: obj.perm, value: obj.perm } |
| ]} |
| /> |
| )} |
| /> |
| </div> |
| ); |
| }) |
| ) : ( |
| <p className="mt-1">--</p> |
| )} |
| </Card.Body> |
| </Accordion.Collapse> |
| </Card> |
| </Accordion> |
| </Card> |
| </div> |
| <Modal |
| show={showAddPrincipalModal} |
| onHide={toggleAddPrincipalModal} |
| size="lg" |
| > |
| <Modal.Header closeButton> |
| <h3 className="gds-header bold">Add Principals</h3> |
| </Modal.Header> |
| <div className="gds-form-input"> |
| <Field |
| className="form-control" |
| name="selectedPrinciple" |
| render={({ input, meta }) => ( |
| <div> |
| <Modal.Body> |
| <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 |
| variant="secondary" |
| size="sm" |
| onClick={() => toggleAddPrincipalModal()} |
| > |
| Close |
| </Button> |
| <Button |
| variant="primary" |
| size="sm" |
| onClick={() => { |
| userOgList; |
| if ( |
| !selectedPrinciple || |
| selectedPrinciple[0] == undefined || |
| selectedPrinciple[0].value == undefined || |
| selectedPrinciple.length === 0 |
| ) { |
| toast.dismiss(toastId.current); |
| toastId.current = toast.error( |
| "Please select principal!!" |
| ); |
| return false; |
| } |
| addInSelectedPrincipal(selectedPrinciple, input); |
| filterPrincipleList( |
| undefined, |
| undefined, |
| undefined, |
| undefined |
| ); |
| }} |
| > |
| Add |
| </Button> |
| </Modal.Footer> |
| </div> |
| )} |
| /> |
| </div> |
| </Modal> |
| </div> |
| ); |
| }; |
| |
| export default PrinciplePermissionComp; |