blob: eeae67d3c139bfb390b59c61b525d2985df10aeb [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, { useReducer, useEffect, useCallback, useState } from "react";
import {
NavLink,
matchRoutes,
useLocation,
useNavigate
} from "react-router-dom";
import Button from "react-bootstrap/Button";
import rangerIcon from "Images/sidebar/ranger.svg";
import keyIcon from "Images/sidebar/key.svg";
import tagsIcon from "Images/sidebar/tags.svg";
import reportsIcon from "Images/sidebar/reports.svg";
import auditsIcon from "Images/sidebar/audits.svg";
import zoneIcon from "Images/sidebar/zone.svg";
import settingsIcon from "Images/sidebar/settings.svg";
import accountIcon from "Images/sidebar/account.svg";
import gdsIcon from "Images/sidebar/governed-data.svg";
import Collapse from "react-bootstrap/Collapse";
import { fetchApi } from "Utils/fetchAPI";
import { getUserProfile, setUserProfile } from "Utils/appState";
import {
hasAccessToTab,
isAuditor,
isKeyAdmin,
isSystemAdmin,
getBaseUrl,
isKMSAuditor
} from "Utils/XAUtils";
import Select from "react-select";
import {
cloneDeep,
filter,
isEmpty,
map,
sortBy,
uniq,
upperCase
} from "lodash";
import { toast } from "react-toastify";
import ResourceTagContent from "./ResourceTagContent";
import { PathAssociateWithModule } from "../../utils/XAEnums";
import { getServiceDef } from "../../utils/appState";
import { SideBarBody } from "./SideBarBody";
import { getLandingPageURl } from "../../utils/XAUtils";
function reducer(state, action) {
switch (action.type) {
case "SET_LOADER":
return {
...state,
loader: action.loader
};
case "SERVICEDEF_DATA":
return {
...state,
allserviceDefData: action.allserviceDefData,
serviceDefData: action.serviceDefData,
tagServiceDefData: action.tagServiceDefData
};
case "SERVICES_DATA":
return {
...state,
allServiceData: action.allServiceData,
serviceData: action.serviceData,
tagServiceData: action.tagServiceData
};
case "SELECTED_SERVCIEDEF_DATA":
return {
...state,
selectedServiceDef: action.selectedServiceDef
};
default:
throw new Error();
}
}
export const SideBar = () => {
const { allServiceDefs, serviceDefs, tagServiceDefs } = cloneDeep(
getServiceDef()
);
const isKMSRole = isKeyAdmin() || isKMSAuditor();
const [keyState, dispatch] = useReducer(reducer, {
loader: false,
allserviceDefData: allServiceDefs,
serviceDefData: serviceDefs,
tagServiceDefData: tagServiceDefs,
allServiceData: [],
serviceData: [],
tagServiceData: [],
selectedServiceDef: [],
serviceTypesOptions: sortBy(
filter(allServiceDefs, (serviceDef) => serviceDef.name !== "tag"),
"name"
)
});
const {
loader,
serviceData,
tagServiceData,
allServiceData,
serviceDefData,
tagServiceDefData,
allserviceDefData
} = keyState;
const userProps = getUserProfile();
const loginId = (
<span className="login-id user-name">{userProps?.loginId}</span>
);
let location = useLocation();
let isListenerAttached = false;
const [isActive, setActive] = useState(null);
const [isDrawerOpen, setDrawer] = useState(false);
const [accountDrawer, setAccountDrawer] = useState(false);
const [isTagView, setTagView] = useState(false);
const handleClickOutside = (e) => {
if (
document.getElementById("sidebar")?.contains(e?.target) == false &&
document.getElementById("drawer-content")?.contains(e?.target) == false &&
document.getElementById("account-drawer-content")?.contains(e?.target) ==
false
) {
setActive(null);
setDrawer(false);
setAccountDrawer(false);
}
e?.stopPropagation();
};
useEffect(() => {
if (
location.pathname != "/policymanager/resource" &&
location.pathname != "/policymanager/tag"
) {
fetchServicesData();
}
}, []);
useEffect(() => {
if (!isListenerAttached) {
document?.addEventListener("mousedown", handleClickOutside);
isListenerAttached = true;
return;
}
return () => {
document?.removeEventListener("mousedown", handleClickOutside);
};
}, []);
const fetchServicesData = async () => {
dispatch({
type: "SET_LOADER",
loader: true
});
let servicesResp = [];
let resourceServices = [];
let tagServices = [];
try {
servicesResp = await fetchApi({
url: "plugins/services"
});
tagServices = filter(servicesResp.data.services, ["type", "tag"]);
if (isKMSRole) {
resourceServices = filter(
servicesResp.data.services,
(service) => service.type == "kms"
);
} else {
resourceServices = filter(
servicesResp.data.services,
(service) => service.type !== "tag" && service.type !== "kms"
);
}
dispatch({
type: "SERVICES_DATA",
allServiceData: servicesResp.data.services,
serviceData: resourceServices,
tagServiceData: tagServices
});
dispatch({
type: "SET_LOADER",
loader: false
});
} catch (error) {
console.error(
`Error occurred while fetching Services or CSRF headers! ${error}`
);
}
};
const closeCollapse = () => {
setActive(null);
setDrawer(false);
setAccountDrawer(false);
};
const activeClass = (modules) => {
let allRouter = [];
let PermissionPath = PathAssociateWithModule["Permission"]?.map((val) => ({
path: val
}));
for (const key in PathAssociateWithModule) {
if (key == modules) {
allRouter = [...allRouter, ...PathAssociateWithModule[key]];
}
}
let isValidRouter = matchRoutes(
allRouter.map((val) => ({ path: val })),
location.pathname
);
if (isValidRouter !== null && isValidRouter.length > 0) {
return "navbar-active";
} else if (
matchRoutes(PermissionPath, location.pathname) &&
modules == "Users/Groups"
) {
return "navbar-active";
} else {
return;
}
};
return (
<React.Fragment>
<nav id="sidebar">
<div className="sidebar-header">
<NavLink
id="rangerIcon"
to={getLandingPageURl()}
onClick={() => {
setActive(null);
setDrawer(false);
setAccountDrawer(false);
}}
>
<img className="logo" src={rangerIcon} alt="Ranger logo" />
</NavLink>
</div>
<ul className="list-unstyled components">
{hasAccessToTab("Resource Based Policies") && (
<li
className={
isActive !== null && isActive === "resourcesCollapse"
? "selected"
: undefined
}
>
<Button
id="resourcesButton"
className={activeClass("Resource Based Policies")}
onClick={() => {
setActive("resourcesCollapse");
setAccountDrawer(false);
setDrawer(true);
setTagView(false);
fetchServicesData();
}}
>
<img src={keyIcon} />
<span>Resource Policies</span>
</Button>
</li>
)}
{hasAccessToTab("Tag Based Policies") && (
<li
className={
isActive !== null && isActive === "tagCollapse"
? "selected"
: undefined
}
>
<Button
id="tagButton"
className={activeClass("Tag Based Policies")}
onClick={() => {
setActive("tagCollapse");
setAccountDrawer(false);
setDrawer(true);
setTagView(true);
fetchServicesData();
}}
>
<img src={tagsIcon} />
<span>Tag Policies</span>
</Button>
</li>
)}
{hasAccessToTab("Governed Data Sharing") && (
<li
className={
isActive !== null && isActive === "gdsCollapse"
? "selected"
: undefined
}
>
<Button
id="gdsButton"
className={activeClass("GDS")}
onClick={() => {
setActive("gdsCollapse");
setAccountDrawer(false);
setDrawer(true);
}}
>
<img src={gdsIcon} />
<span>Governed Data Sharing</span>
</Button>
</li>
)}
{hasAccessToTab("Reports") && (
<li>
<NavLink
to="/reports/userAccess?policyType=0"
className={activeClass("Reports")}
onClick={() => {
setActive(null);
setDrawer(false);
setAccountDrawer(false);
}}
>
<img src={reportsIcon} />
<span>Reports</span>
</NavLink>
</li>
)}
{hasAccessToTab("Audit") && (
<li
className={
isActive !== null && isActive === "auditCollapse"
? "selected"
: undefined
}
>
<Button
className={activeClass("Audit")}
onClick={() => {
setActive("auditCollapse");
setAccountDrawer(false);
setDrawer(true);
}}
>
<img src={auditsIcon} />
<span>Audits</span>
</Button>
</li>
)}
{hasAccessToTab("Security Zone") && (
<React.Fragment>
{!isKMSRole && (
<li>
<NavLink
className={activeClass("Security Zone")}
to="/zones/zone/list"
onClick={() => {
setActive(null);
setDrawer(false);
setAccountDrawer(false);
}}
>
<img src={zoneIcon} />
<span>Security Zone</span>
</NavLink>
</li>
)}
</React.Fragment>
)}
{hasAccessToTab("Key Manager") && (
<React.Fragment>
<li>
<NavLink
className={activeClass("Key Manager")}
to="/kms/keys/new/manage/service"
onClick={() => {
setActive(null);
setDrawer(false);
setAccountDrawer(false);
}}
>
<i className="fa fa-fw fa-key"></i>
<span>Key Manager</span>
</NavLink>
</li>
</React.Fragment>
)}
{(hasAccessToTab("Users/Groups") ||
isAuditor() ||
isSystemAdmin()) && (
<li
className={
isActive !== null && isActive === "settingsCollapse"
? "selected"
: undefined
}
>
<Button
className={activeClass("Users/Groups")}
onClick={() => {
setActive("settingsCollapse");
setAccountDrawer(false);
setDrawer(true);
}}
>
<img src={settingsIcon} />
<span>Settings</span>
</Button>
</li>
)}
<li
className={
isActive !== null && isActive === "accountCollapse"
? "selected"
: undefined
}
>
<Button
className={activeClass("Profile")}
onClick={() => {
setActive("accountCollapse");
setDrawer(false);
setAccountDrawer(true);
}}
>
<img src={accountIcon} />
<span title={userProps?.loginId}>{loginId}</span>
</Button>
</li>
</ul>
</nav>
<SideBarBody
allServicesDefData={allserviceDefData}
servicesDefData={serviceDefData}
tagServicesDefData={tagServiceDefData}
allServicesData={allServiceData}
servicesData={serviceData}
tagServicesData={tagServiceData}
loader={loader}
activeMenu={isActive}
isDrawerOpen={isDrawerOpen}
accountDrawer={accountDrawer}
closeCollapse={closeCollapse}
sideBarDispatch={dispatch}
/>
</React.Fragment>
);
};
export default SideBar;