From 7c6beecdcbcfdda9c93aaffd85d7a526ab4a137d Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Tue, 6 Feb 2024 15:25:05 +0530 Subject: [PATCH] feat: Add access control all over codebase (#281) Co-authored-by: Jeeva Ramachandran <120017870+JeevaRamu0104@users.noreply.github.com> --- src/components/ACLDiv.res | 29 +++++++++ src/components/ACLDiv.resi | 14 +++++ src/components/tooltip/ACLToolTip.res | 58 ++++++++++++++++++ src/components/tooltip/ACLToolTip.resi | 28 +++++++++ .../HyperSwitch/Connectors/ConnectorList.res | 35 +++++++---- src/screens/HyperSwitch/Home/HomeUtils.res | 1 + src/screens/HyperSwitch/Home/HomeV2.res | 60 +++++++++++++------ .../UserManagement/InviteUsers.res | 5 -- .../UserManagement/PermissionUtils.res | 2 + 9 files changed, 197 insertions(+), 35 deletions(-) create mode 100644 src/components/ACLDiv.res create mode 100644 src/components/ACLDiv.resi create mode 100644 src/components/tooltip/ACLToolTip.res create mode 100644 src/components/tooltip/ACLToolTip.resi diff --git a/src/components/ACLDiv.res b/src/components/ACLDiv.res new file mode 100644 index 000000000..0606985cc --- /dev/null +++ b/src/components/ACLDiv.res @@ -0,0 +1,29 @@ +@react.component +let make = ( + ~permission, + ~onClick, + ~children, + ~className="", + ~noAccessDescription=?, + ~description=?, + ~tooltipWidthClass=?, + ~isRelative=?, + ~contentAlign=?, + ~justifyClass=?, + ~tooltipForWidthClass=?, +) => { + ()}}> + {children} + } + toolTipPosition={Top} + /> +} diff --git a/src/components/ACLDiv.resi b/src/components/ACLDiv.resi new file mode 100644 index 000000000..4e1088798 --- /dev/null +++ b/src/components/ACLDiv.resi @@ -0,0 +1,14 @@ +@react.component +let make: ( + ~permission: AuthTypes.authorization, + ~onClick: JsxEvent.Mouse.t => unit, + ~children: React.element, + ~className: string=?, + ~noAccessDescription: string=?, + ~description: string=?, + ~tooltipWidthClass: string=?, + ~isRelative: bool=?, + ~contentAlign: ToolTip.contentPosition=?, + ~justifyClass: string=?, + ~tooltipForWidthClass: string=?, +) => React.element diff --git a/src/components/tooltip/ACLToolTip.res b/src/components/tooltip/ACLToolTip.res new file mode 100644 index 000000000..0e7e59ebe --- /dev/null +++ b/src/components/tooltip/ACLToolTip.res @@ -0,0 +1,58 @@ +open ToolTip + +@react.component +let make = ( + ~access, + ~noAccessDescription=HSwitchUtils.noAccessControlText, + ~description="", + ~descriptionComponent=React.null, + ~tooltipPositioning: tooltipPositioning=#fixed, + ~toolTipFor=?, + ~tooltipWidthClass="w-fit", + ~tooltipForWidthClass="", + ~toolTipPosition: option=?, + ~customStyle="", + ~arrowCustomStyle="", + ~textStyleGap="", + ~arrowBgClass="", + ~bgColor="", + ~contentAlign: contentPosition=Middle, + ~justifyClass="justify-center", + ~flexClass="flex-col", + ~height="h-full", + ~textStyle="text-fs-11", + ~hoverOnToolTip=false, + ~tooltipArrowSize=5, + ~visibleOnClick=false, + ~descriptionComponentClass="flex flex-row-reverse", + ~isRelative=true, + ~dismissable=false, +) => { + let description = access === AuthTypes.Access ? description : noAccessDescription + + +} diff --git a/src/components/tooltip/ACLToolTip.resi b/src/components/tooltip/ACLToolTip.resi new file mode 100644 index 000000000..732ea3e1b --- /dev/null +++ b/src/components/tooltip/ACLToolTip.resi @@ -0,0 +1,28 @@ +@react.component +let make: ( + ~access: AuthTypes.authorization, + ~noAccessDescription: string=?, + ~description: string=?, + ~descriptionComponent: React.element=?, + ~tooltipPositioning: ToolTip.tooltipPositioning=?, + ~toolTipFor: React.element=?, + ~tooltipWidthClass: string=?, + ~tooltipForWidthClass: string=?, + ~toolTipPosition: ToolTip.toolTipPosition=?, + ~customStyle: string=?, + ~arrowCustomStyle: string=?, + ~textStyleGap: string=?, + ~arrowBgClass: string=?, + ~bgColor: string=?, + ~contentAlign: ToolTip.contentPosition=?, + ~justifyClass: string=?, + ~flexClass: string=?, + ~height: string=?, + ~textStyle: string=?, + ~hoverOnToolTip: bool=?, + ~tooltipArrowSize: int=?, + ~visibleOnClick: bool=?, + ~descriptionComponentClass: string=?, + ~isRelative: bool=?, + ~dismissable: bool=?, +) => React.element diff --git a/src/screens/HyperSwitch/Connectors/ConnectorList.res b/src/screens/HyperSwitch/Connectors/ConnectorList.res index ca6b07ecd..84134032b 100644 --- a/src/screens/HyperSwitch/Connectors/ConnectorList.res +++ b/src/screens/HyperSwitch/Connectors/ConnectorList.res @@ -24,12 +24,16 @@ module RequestConnector = { module CantFindProcessor = { @react.component let make = (~showRequestConnectorBtn, ~setShowModal) => { + let userPermissionJson = Recoil.useRecoilValueFromAtom(HyperswitchAtom.userPermissionAtom) + let cursorStyles = PermissionUtils.cursorStyles(userPermissionJson.merchantAccountWrite) + -
setShowModal(_ => true)} - className={`text-blue-900 underline underline-offset-4 font-medium`}> + className={`text-blue-900 underline underline-offset-4 font-medium ${cursorStyles}`}> {"Can't find the processor of your choice?"->React.string} -
+
} } @@ -178,19 +182,26 @@ module NewProcessorCards = { {connectorList ->Array.mapWithIndex((connector, i) => { let connectorName = connector->getConnectorNameString - let size = "w-14 h-14 rounded-sm" - string_of_int} + permission=userPermissionJson.merchantConnectorAccountWrite + className={`p-2 ${cursorStyles}`} + noAccessDescription=noAccessControlTextForProcessors + tooltipWidthClass="w-30" description={connectorName->getDisplayNameForConnectors} - toolTipFor={String.toLowerCase)]> + onClick={_ => handleClick(connectorName)}> + String.toLowerCase)]>
handleClick(connectorName)}> - String.toUpperCase} className=size /> + String.toUpperCase} className="w-14 h-14 rounded-sm" + />
-
} - toolTipPosition={Top} - tooltipWidthClass="w-30" - /> +
+ }) ->React.array} diff --git a/src/screens/HyperSwitch/Home/HomeUtils.res b/src/screens/HyperSwitch/Home/HomeUtils.res index a8afd3c7c..00be4542a 100644 --- a/src/screens/HyperSwitch/Home/HomeUtils.res +++ b/src/screens/HyperSwitch/Home/HomeUtils.res @@ -21,6 +21,7 @@ type resourcesTypes = { subText: string, redirectLink: string, id: string, + access: AuthTypes.authorization, } let countries: array = [ diff --git a/src/screens/HyperSwitch/Home/HomeV2.res b/src/screens/HyperSwitch/Home/HomeV2.res index 3fc147e42..e59b9c6c6 100644 --- a/src/screens/HyperSwitch/Home/HomeV2.res +++ b/src/screens/HyperSwitch/Home/HomeV2.res @@ -221,11 +221,20 @@ module RecipesAndPlugins = { ->QuickStartUtils.getTypedValueFromDict let isStripePlusPayPalCompleted = enumDetails->checkStripePlusPayPal let isWooCommercePalCompleted = enumDetails->checkWooCommerce + let userPermissionJson = Recoil.useRecoilValueFromAtom(HyperswitchAtom.userPermissionAtom) + // TODO :: Need to re-evaluate the condition + let blockConditionAccessVal = + userPermissionJson.merchantConnectorAccountRead === NoAccess && + userPermissionJson.merchantConnectorAccountWrite === NoAccess + ? AuthTypes.NoAccess + : AuthTypes.Access

{"Recipes & Plugins"->React.string}

-
{ mixpanelEvent(~eventName=`stripe_plus_paypal`, ()) @@ -250,8 +259,10 @@ module RecipesAndPlugins = {

-
-
+ { mixpanelEvent(~eventName=`woocommerce`, ()) @@ -276,7 +287,7 @@ module RecipesAndPlugins = {

-
+ } @@ -286,6 +297,7 @@ module Resources = { @react.component let make = () => { let mixpanelEvent = MixpanelHook.useSendEvent() + let userPermissionJson = Recoil.useRecoilValueFromAtom(HyperswitchAtom.userPermissionAtom) let elements: array = [ { id: "tryTheDemo", @@ -293,6 +305,7 @@ module Resources = { headerText: "Try a test payment", subText: "Experience the Hyperswitch Unified checkout using test credentials", redirectLink: "", + access: userPermissionJson.paymentWrite, }, { id: "openSource", @@ -300,6 +313,7 @@ module Resources = { headerText: "Contribute in open source", subText: "We welcome all your suggestions, feedbacks, and queries. Hop on to the Open source rail!", redirectLink: "", + access: Access, }, { id: "developerdocs", @@ -307,28 +321,38 @@ module Resources = { headerText: "Developer docs", subText: "Everything you need to know to get to get the SDK up and running resides in here.", redirectLink: "", + access: Access, }, ] + + let onClickHandler = item => { + if item.id === "openSource" { + mixpanelEvent(~eventName=`contribute_in_open_source`, ()) + "https://github.com/juspay/hyperswitch"->Window._open + } else if item.id === "developerdocs" { + mixpanelEvent(~eventName=`dev_docs`, ()) + "https://hyperswitch.io/docs"->Window._open + } else if item.id === "tryTheDemo" { + RescriptReactRouter.replace("/sdk") + } + } + <>

{"Resources"->React.string}

{elements ->Array.mapWithIndex((item, index) => { -
string_of_int} - onClick={_ => { - if item.id === "openSource" { - mixpanelEvent(~eventName=`contribute_in_open_source`, ()) - "https://github.com/juspay/hyperswitch"->Window._open - } else if item.id === "developerdocs" { - mixpanelEvent(~eventName=`dev_docs`, ()) - "https://hyperswitch.io/docs"->Window._open - } else if item.id === "tryTheDemo" { - RescriptReactRouter.replace("/sdk") - } - }}> + permission=item.access + isRelative=false + contentAlign=Default + tooltipForWidthClass="!h-full" + justifyClass="" + className={`!h-full group bg-white border rounded-md p-10 flex flex-col gap-4 group-hover:shadow hover:shadow-homePageBoxShadow ${cursorStyles}`} + onClick={_ => onClickHandler(item)}>

{item.headerText->React.string}

@@ -339,7 +363,7 @@ module Resources = { />

{item.subText->React.string}

-
+ }) ->React.array}
diff --git a/src/screens/HyperSwitch/UserManagement/InviteUsers.res b/src/screens/HyperSwitch/UserManagement/InviteUsers.res index a46320e9f..7ba861e80 100644 --- a/src/screens/HyperSwitch/UserManagement/InviteUsers.res +++ b/src/screens/HyperSwitch/UserManagement/InviteUsers.res @@ -8,10 +8,6 @@ module InviteEmailForm = { let {magicLink} = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom let (roleListData, setRoleListData) = React.useState(_ => []) - let emailList = - ReactFinalForm.useField("emailList").input.value - ->getArrayFromJson([]) - ->Array.joinWithUnsafe(",") let role = ReactFinalForm.useField(`roleType`).input.value ->getArrayFromJson([]) @@ -53,7 +49,6 @@ module InviteEmailForm = { fieldWrapperClass="w-4/5" labelClass="!text-black !text-base !-ml-[0.5px]" /> -
{emailList->React.string}
diff --git a/src/screens/HyperSwitch/UserManagement/PermissionUtils.res b/src/screens/HyperSwitch/UserManagement/PermissionUtils.res index d9735d68c..34eea349a 100644 --- a/src/screens/HyperSwitch/UserManagement/PermissionUtils.res +++ b/src/screens/HyperSwitch/UserManagement/PermissionUtils.res @@ -208,3 +208,5 @@ let getPermissionJson = permissionList => { let linkForGetShowLinkViaAccess = (~permission, ~url) => { permission === Access ? url : `` } + +let cursorStyles = permission => permission === Access ? "cursor-pointer" : "cursor-not-allowed"