diff --git a/app/client/src/ce/components/SwitchEnvironment/index.tsx b/app/client/src/ce/components/SwitchEnvironment/index.tsx index e17c566866..e38069dbd4 100644 --- a/app/client/src/ce/components/SwitchEnvironment/index.tsx +++ b/app/client/src/ce/components/SwitchEnvironment/index.tsx @@ -9,11 +9,15 @@ import { SWITCH_ENV_DISABLED_TOOLTIP_TEXT, createMessage, } from "@appsmith/constants/messages"; -import { getRampLink, showProductRamps } from "utils/ProductRamps"; +import { getRampLink, showProductRamps } from "selectors/rampSelectors"; import { isDatasourceInViewMode } from "selectors/ui"; import { matchDatasourcePath, matchSAASGsheetsPath } from "constants/routes"; import { useLocation } from "react-router"; -import { RAMP_NAME, RampFeature } from "utils/ProductRamps/RampsControlList"; +import { + RAMP_NAME, + RampFeature, + RampSection, +} from "utils/ProductRamps/RampsControlList"; const Wrapper = styled.div` display: flex; @@ -71,7 +75,13 @@ export default function SwitchEnvironment({}: Props) { const [diableSwitchEnvironment, setDiableSwitchEnvironment] = useState(false); // Fetching feature flags from the store and checking if the feature is enabled const allowedToRender = useSelector(datasourceEnvEnabled); - const showRamps = showProductRamps(RAMP_NAME.MULTIPLE_ENV); + const showRampSelector = showProductRamps(RAMP_NAME.MULTIPLE_ENV); + const canShowRamp = useSelector(showRampSelector); + const rampLinkSelector = getRampLink({ + section: RampSection.BottomBarEnvSwitcher, + feature: RampFeature.MultipleEnv, + }); + const rampLink = useSelector(rampLinkSelector); const location = useLocation(); //listen to url change and disable switch environment if datasource page is open useEffect(() => { @@ -84,7 +94,7 @@ export default function SwitchEnvironment({}: Props) { //this parameter helps us to differentiate between the two. const isDatasourceViewMode = useSelector(isDatasourceInViewMode); - if (!allowedToRender || !showRamps) return null; + if (!allowedToRender || !canShowRamp) return null; const renderEnvOption = (env: EnvironmentType) => { return ( @@ -101,11 +111,7 @@ export default function SwitchEnvironment({}: Props) { return ( {createMessage(SWITCH_ENV_DISABLED_TOOLTIP_TEXT)} - + {createMessage(BUSINESS_EDITION_TEXT)} diff --git a/app/client/src/ce/components/editorComponents/DSDataFilter/index.tsx b/app/client/src/ce/components/editorComponents/DSDataFilter/index.tsx index cd90c56e41..174437668b 100644 --- a/app/client/src/ce/components/editorComponents/DSDataFilter/index.tsx +++ b/app/client/src/ce/components/editorComponents/DSDataFilter/index.tsx @@ -10,8 +10,12 @@ import { createMessage, } from "@appsmith/constants/messages"; import { capitalizeFirstLetter } from "utils/helpers"; -import { getRampLink, showProductRamps } from "utils/ProductRamps"; -import { RAMP_NAME, RampFeature } from "utils/ProductRamps/RampsControlList"; +import { getRampLink, showProductRamps } from "selectors/rampSelectors"; +import { + RAMP_NAME, + RampFeature, + RampSection, +} from "utils/ProductRamps/RampsControlList"; const Container = styled.div` display: flex; @@ -90,14 +94,21 @@ function DSDataFilter({ }: DSDataFilterProps) { const [showFilterPane, setShowFilterPane] = useState(false); const datasourceEnv: boolean = useSelector(datasourceEnvEnabled); - const showRamps = showProductRamps(RAMP_NAME.MULTIPLE_ENV); + const showRampSelector = showProductRamps(RAMP_NAME.MULTIPLE_ENV); + const canShowRamp = useSelector(showRampSelector); + + const rampLinkSelector = getRampLink({ + section: RampSection.DSEditor, + feature: RampFeature.MultipleEnv, + }); + const rampLink = useSelector(rampLinkSelector); // update the selected environment if the list of environments changes useEffect(() => { const isRenderAllowed = environments.length > 0 && datasourceEnv && - showRamps && + canShowRamp && !viewMode && !isInsideReconnectModal; @@ -149,11 +160,7 @@ function DSDataFilter({ return ( {createMessage(SWITCH_ENV_DISABLED_TOOLTIP_TEXT)} - + {createMessage(BUSINESS_EDITION_TEXT)} diff --git a/app/client/src/ce/pages/workspace/Members.tsx b/app/client/src/ce/pages/workspace/Members.tsx index b2a9214f83..d7350be9a9 100644 --- a/app/client/src/ce/pages/workspace/Members.tsx +++ b/app/client/src/ce/pages/workspace/Members.tsx @@ -38,7 +38,7 @@ import { } from "@appsmith/utils/permissionHelpers"; import { getInitials } from "utils/AppsmithUtils"; import { CustomRolesRamp } from "./WorkspaceInviteUsersForm"; -import { showProductRamps } from "utils/ProductRamps"; +import { showProductRamps } from "selectors/rampSelectors"; import { RAMP_NAME } from "utils/ProductRamps/RampsControlList"; const { cloudHosting } = getAppsmithConfigs(); @@ -200,6 +200,9 @@ export default function MemberSettings(props: PageProps) { const dispatch = useDispatch(); const history = useHistory(); + const showRampSelector = showProductRamps(RAMP_NAME.CUSTOM_ROLES); + const canShowRamp = useSelector(showRampSelector); + useEffect(() => { dispatch(fetchUsersForWorkspace(workspaceId)); dispatch(fetchRolesForWorkspace(workspaceId)); @@ -416,7 +419,7 @@ export default function MemberSettings(props: PageProps) { ))} - {showProductRamps(RAMP_NAME.CUSTOM_ROLES) && ( + {canShowRamp && ( @@ -559,7 +562,7 @@ export default function MemberSettings(props: PageProps) { ))} - {showProductRamps(RAMP_NAME.CUSTOM_ROLES) && ( + {canShowRamp && ( diff --git a/app/client/src/ce/pages/workspace/WorkspaceInviteUsersForm.tsx b/app/client/src/ce/pages/workspace/WorkspaceInviteUsersForm.tsx index 0438fb2a08..7bc235b6e7 100644 --- a/app/client/src/ce/pages/workspace/WorkspaceInviteUsersForm.tsx +++ b/app/client/src/ce/pages/workspace/WorkspaceInviteUsersForm.tsx @@ -58,8 +58,12 @@ import { import { USER_PHOTO_ASSET_URL } from "constants/userConstants"; import { importSvg } from "design-system-old"; import type { WorkspaceUserRoles } from "@appsmith/constants/workspaceConstants"; -import { getRampLink, showProductRamps } from "utils/ProductRamps"; -import { RAMP_NAME } from "utils/ProductRamps/RampsControlList"; +import { getRampLink, showProductRamps } from "selectors/rampSelectors"; +import { + RAMP_NAME, + RampFeature, + RampSection, +} from "utils/ProductRamps/RampsControlList"; import BusinessTag from "components/BusinessTag"; const NoEmailConfigImage = importSvg( @@ -255,16 +259,23 @@ function InviteUserText({ }: { isApplicationInvite: boolean; }) { + const rampLinkSelector = getRampLink({ + section: RampSection.AppShare, + feature: RampFeature.Gac, + }); + const rampLink = useSelector(rampLinkSelector); + const showRampSelector = showProductRamps(RAMP_NAME.INVITE_USER_TO_APP); + const canShowRamp = useSelector(showRampSelector); return ( - {showProductRamps(RAMP_NAME.INVITE_USER_TO_APP) && isApplicationInvite ? ( + {canShowRamp && isApplicationInvite ? ( <> {createMessage(INVITE_USER_RAMP_TEXT)} - + {createMessage(BUSINESS_EDITION_TEXT)} @@ -277,6 +288,11 @@ function InviteUserText({ export function CustomRolesRamp() { const [dynamicProps, setDynamicProps] = useState({}); + const rampLinkSelector = getRampLink({ + section: RampSection.WorkspaceShare, + feature: RampFeature.Gac, + }); + const rampLink = useSelector(rampLinkSelector); const rampText = ( {createMessage(CUSTOM_ROLES_RAMP_TEXT)}{" "} @@ -285,7 +301,7 @@ export function CustomRolesRamp() { kind="primary" onClick={() => { setDynamicProps({ visible: false }); - window.open(getRampLink("workspace_share"), "_blank"); + window.open(rampLink, "_blank"); // This reset of prop is required because, else the tooltip will be controlled by the state setTimeout(() => { setDynamicProps({}); @@ -324,6 +340,9 @@ function WorkspaceInviteUsersForm(props: any) { // const history = useHistory(); const selectedId = props?.selected?.id; + const showRampSelector = showProductRamps(RAMP_NAME.CUSTOM_ROLES); + const canShowRamp = useSelector(showRampSelector); + const selected = useMemo( () => selectedId && @@ -539,7 +558,7 @@ function WorkspaceInviteUsersForm(props: any) { ))} - {showProductRamps(RAMP_NAME.CUSTOM_ROLES) && ( + {canShowRamp && ( diff --git a/app/client/src/pages/AppViewer/index.tsx b/app/client/src/pages/AppViewer/index.tsx index 70aa2a5961..b49ffbe073 100644 --- a/app/client/src/pages/AppViewer/index.tsx +++ b/app/client/src/pages/AppViewer/index.tsx @@ -50,7 +50,7 @@ import { } from "@design-system/theming"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { RAMP_NAME } from "utils/ProductRamps/RampsControlList"; -import { showProductRamps } from "utils/ProductRamps"; +import { showProductRamps } from "selectors/rampSelectors"; import { isCEMode } from "@appsmith/utils"; const AppViewerBody = styled.section<{ @@ -112,12 +112,15 @@ function AppViewer(props: Props) { }); const focusRef = useWidgetFocus(); + const showRampSelector = showProductRamps(RAMP_NAME.MULTIPLE_ENV); + const canShowRamp = useSelector(showRampSelector); + const workspaceId = currentApplicationDetails?.workspaceId || ""; const showBottomBar = useSelector((state: AppState) => { return ( areEnvironmentsFetched(state, workspaceId) && datasourceEnvEnabled(state) && - (isCEMode() ? showProductRamps(RAMP_NAME.MULTIPLE_ENV) : true) + (isCEMode() ? canShowRamp : true) ); }); diff --git a/app/client/src/utils/ProductRamps/index.test.ts b/app/client/src/utils/ProductRamps/index.test.ts deleted file mode 100644 index 253e4f36c4..0000000000 --- a/app/client/src/utils/ProductRamps/index.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import store from "store"; -import { - PRODUCT_RAMPS_LIST, - getUserRoleInWorkspace, - showProductRamps, -} from "."; -import { RAMP_FOR_ROLES, RAMP_NAME } from "./RampsControlList"; -import type { SupportedRampsType } from "./RampTypes"; - -jest.mock("store"); - -describe("getUserRoleInWorkspace", () => { - test("should return Super User role when isSuperUser is true", () => { - const stateMock = { - ui: { - users: { - currentUser: { - isSuperUser: true, - }, - }, - }, - }; - (store.getState as jest.Mock).mockReturnValue(stateMock); - - const result = getUserRoleInWorkspace(); - expect(result).toBe(RAMP_FOR_ROLES.SUPER_USER); - }); - - test("should return the role when isSuperUser is false and workspaceUsers has roles", () => { - const roles = ["Administrator", "Developer", "App Viewer"]; - - roles.forEach((role) => { - const stateMock = { - ui: { - users: { - currentUser: { - isSuperUser: false, - username: "testuser", - }, - }, - workspaces: { - workspaceUsers: [ - { - username: "testuser", - roles: [ - { - name: `${role}-role`, - }, - ], - }, - ], - }, - }, - }; - (store.getState as jest.Mock).mockReturnValue(stateMock); - - const result = getUserRoleInWorkspace(); - expect(result).toBe(role); - }); - }); -}); - -describe("showProductRamps", () => { - test("should return false when rampName is not in PRODUCT_RAMPS_LIST", () => { - const stateMock = { - ui: { - users: { - currentUser: { - isSuperUser: true, - }, - }, - }, - }; - (store.getState as jest.Mock).mockReturnValue(stateMock); - const rampName = "INVALID_RAMP"; - const result = showProductRamps(rampName); - expect(result).toBe(false); - }); - - test("should return the correct rampConfig based on role and env", () => { - const rampNames = [RAMP_NAME.INVITE_USER_TO_APP, RAMP_NAME.CUSTOM_ROLES]; - const envs = ["SELF_HOSTED", "CLOUD_HOSTED"]; - const roles = ["Administrator", "Developer", "App Viewer"]; - rampNames.forEach((ramp) => { - envs.forEach((env) => { - roles.forEach((role) => { - (store.getState as jest.Mock).mockReturnValueOnce({ - ui: { - users: { - currentUser: { - isSuperUser: false, - username: "testuser", - }, - }, - workspaces: { - workspaceUsers: [ - { - username: "testuser", - roles: [ - { - name: `${role}-role`, - }, - ], - }, - ], - }, - }, - }); - const result = showProductRamps(ramp); - const expected = - PRODUCT_RAMPS_LIST[ramp][env as keyof SupportedRampsType][role]; - expect(result).toBe(expected); - }); - }); - }); - }); -}); diff --git a/app/client/src/utils/ProductRamps/index.ts b/app/client/src/utils/ProductRamps/index.ts index cf13eb6c62..1ce770270a 100644 --- a/app/client/src/utils/ProductRamps/index.ts +++ b/app/client/src/utils/ProductRamps/index.ts @@ -1,60 +1,13 @@ -import { PRICING_PAGE_URL } from "constants/ThirdPartyConstants"; -import type { EnvTypes, RampSection, SupportedRampsType } from "./RampTypes"; +import type { SupportedRampsType } from "./RampTypes"; import { CUSTOM_ROLES, INVITE_USER_TO_APP, MULTIPLE_ENV, - RAMP_FOR_ROLES, RAMP_NAME, - RampFeature, } from "./RampsControlList"; -import { getAppsmithConfigs } from "@appsmith/configs"; -import store from "store"; - -const { cloudHosting, pricingUrl } = getAppsmithConfigs(); export const PRODUCT_RAMPS_LIST: { [key: string]: SupportedRampsType } = { [RAMP_NAME.INVITE_USER_TO_APP]: INVITE_USER_TO_APP, [RAMP_NAME.CUSTOM_ROLES]: CUSTOM_ROLES, [RAMP_NAME.MULTIPLE_ENV]: MULTIPLE_ENV, }; - -export const getRampLink = ( - section: RampSection, - feature: RampFeature = RampFeature.Gac, -) => { - const state = store.getState(); - const instanceId = state?.tenant?.instanceId; - const source = cloudHosting ? "cloud" : "CE"; - const RAMP_LINK_TO = PRICING_PAGE_URL(pricingUrl, source, instanceId); - return `${RAMP_LINK_TO}&feature=${feature}§ion=${section}`; -}; - -export const getUserRoleInWorkspace = () => { - const state = store.getState(); - const { currentUser } = state?.ui?.users; - const isSuperUser = currentUser?.isSuperUser; - if (isSuperUser) return RAMP_FOR_ROLES.SUPER_USER; - const workspaceUsers = state?.ui?.workspaces?.workspaceUsers; - if (workspaceUsers?.length) { - const workspaceUser = workspaceUsers.find( - (user: any) => user?.username === currentUser?.username, - ); - if (workspaceUser?.roles?.length) { - const [role] = workspaceUser.roles[0]?.name?.split("-"); - if (role) { - return role.trim(); - } - } - } else return RAMP_FOR_ROLES.APP_VIEWER; -}; - -export const showProductRamps = (rampName: string) => { - const role = getUserRoleInWorkspace(); - const env: EnvTypes = cloudHosting ? "CLOUD_HOSTED" : "SELF_HOSTED"; - if (rampName in PRODUCT_RAMPS_LIST) { - const rampConfig = PRODUCT_RAMPS_LIST[rampName][env]; - return rampConfig[role]; - } - return false; -};