From 6c0dc2e89fea48bcc0d833beaff3853ae205d90d Mon Sep 17 00:00:00 2001 From: Dipyaman Biswas Date: Sat, 30 Sep 2023 02:12:56 +0530 Subject: [PATCH] feat: code split files based on feature flags (#27678) ## Description Add feature flag based logic for code splitted files #### PR fixes following issue(s) Fixes #2237 #### Type of change - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [x] Manual - [ ] JUnit - [ ] Jest - [x] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed --- app/client/src/ce/AppRouter.tsx | 12 +- app/client/src/ce/entities/FeatureFlag.ts | 2 + .../pages/AdminSettings/WithSuperUserHoc.tsx | 7 +- .../src/ce/pages/Applications/index.tsx | 10 +- .../BusinessFeatures/adminSettingsHelpers.tsx | 30 ++++ .../permissionPageHelpers.tsx | 143 ++++++++++++++++++ .../src/ce/utils/adminSettingsHelpers.ts | 2 +- app/client/src/ce/utils/planHelpers.ts | 4 + .../ActionRightPane/index.tsx | 11 +- .../GlobalSearch/GlobalSearchHooks.tsx | 27 ++-- .../fields/EmbeddedDatasourcePathField.tsx | 30 +++- .../BusinessFeatures/adminSettingsHelpers.tsx | 1 + .../permissionPageHelpers.tsx | 1 + .../src/pages/AdminSettings/LeftPane.tsx | 10 +- app/client/src/pages/AdminSettings/Main.tsx | 15 +- .../Editor/APIEditor/ApiAuthentication.tsx | 18 ++- .../Editor/APIEditor/CommonEditorForm.tsx | 22 ++- .../AppSettings/PageSettings.tsx | 16 +- .../DatasourceViewModeSchema.tsx | 26 ++-- .../RestAPIDatasourceForm.tsx | 16 +- .../SaveOrDiscardDatasourceModal.tsx | 8 +- .../pages/Editor/DataSourceEditor/index.tsx | 30 ++-- .../Editor/Explorer/Actions/ActionEntity.tsx | 22 ++- .../src/pages/Editor/Explorer/Datasources.tsx | 18 ++- .../Datasources/DataSourceContextMenu.tsx | 18 ++- .../Datasources/DatasourceStructure.tsx | 13 +- .../Editor/Explorer/EntityExplorer.test.tsx | 19 ++- .../pages/Editor/Explorer/Files/Submenu.tsx | 13 +- .../src/pages/Editor/Explorer/Files/index.tsx | 11 +- .../Explorer/JSActions/JSActionEntity.tsx | 20 ++- .../pages/Editor/Explorer/Libraries/index.tsx | 15 +- .../Editor/Explorer/Pages/PageContextMenu.tsx | 29 +++- .../src/pages/Editor/Explorer/Pages/index.tsx | 24 ++- .../Editor/Explorer/Widgets/WidgetEntity.tsx | 11 +- .../Editor/Explorer/Widgets/WidgetGroup.tsx | 11 +- .../GeneratePageForm/GeneratePageForm.tsx | 9 +- .../IntegrationEditor/ActiveDataSources.tsx | 9 +- .../IntegrationEditor/DatasourceCard.tsx | 36 +++-- .../IntegrationsHomeScreen.tsx | 10 +- app/client/src/pages/Editor/JSEditor/Form.tsx | 23 ++- .../Editor/QueryEditor/EditorJSONtoForm.tsx | 29 ++-- .../Editor/SaaSEditor/DatasourceForm.tsx | 31 ++-- .../Editor/SaaSEditor/GoogleSheetSchema.tsx | 26 ++-- .../src/pages/Home/LeftPaneBottomSection.tsx | 43 +++--- app/client/src/pages/common/MobileSidebar.tsx | 12 +- .../src/pages/common/datasourceAuth/index.tsx | 10 +- app/client/src/sagas/ApiPaneSagas.ts | 13 +- app/client/src/sagas/PageSagas.tsx | 13 +- app/client/src/sagas/QueryPaneSagas.ts | 12 +- 49 files changed, 709 insertions(+), 232 deletions(-) create mode 100644 app/client/src/ce/utils/BusinessFeatures/adminSettingsHelpers.tsx create mode 100644 app/client/src/ce/utils/BusinessFeatures/permissionPageHelpers.tsx create mode 100644 app/client/src/ee/utils/BusinessFeatures/adminSettingsHelpers.tsx create mode 100644 app/client/src/ee/utils/BusinessFeatures/permissionPageHelpers.tsx diff --git a/app/client/src/ce/AppRouter.tsx b/app/client/src/ce/AppRouter.tsx index ca6ed28f1e..628d1654a4 100644 --- a/app/client/src/ce/AppRouter.tsx +++ b/app/client/src/ce/AppRouter.tsx @@ -56,7 +56,6 @@ import { fetchProductAlertInit, } from "actions/userActions"; import { getCurrentTenant } from "@appsmith/actions/tenantActions"; -import { getDefaultAdminSettingsPath } from "@appsmith/utils/adminSettingsHelpers"; import { getCurrentUser as getCurrentUserSelector } from "selectors/usersSelectors"; import { getTenantPermissions, @@ -67,6 +66,9 @@ import RouteChangeListener from "RouteChangeListener"; import { initCurrentPage } from "../actions/initActions"; import Walkthrough from "components/featureWalkthrough"; import ProductAlertBanner from "components/editorComponents/ProductAlertBanner"; +import { getAdminSettingsPath } from "@appsmith/utils/BusinessFeatures/adminSettingsHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; export const SentryRoute = Sentry.withSentryRouting(Route); @@ -75,6 +77,7 @@ export const loadingIndicator = ; export function Routes() { const user = useSelector(getCurrentUserSelector); const tenantPermissions = useSelector(getTenantPermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); return ( @@ -99,10 +102,11 @@ export function Routes() { to={ !user ? ADMIN_SETTINGS_PATH - : getDefaultAdminSettingsPath({ - isSuperUser: user?.isSuperUser || false, + : getAdminSettingsPath( + isFeatureEnabled, + user?.isSuperUser || false, tenantPermissions, - }) + ) } /> , ) { return function Wrapped(props: RouteComponentProps) { const user = useSelector(getCurrentUser); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); if (!user) return null; - if (!showAdminSettings(user)) { + if (!getShowAdminSettings(isFeatureEnabled, user)) { return ; } return ; diff --git a/app/client/src/ce/pages/Applications/index.tsx b/app/client/src/ce/pages/Applications/index.tsx index 9b6a238176..902cd592c0 100644 --- a/app/client/src/ce/pages/Applications/index.tsx +++ b/app/client/src/ce/pages/Applications/index.tsx @@ -86,7 +86,6 @@ import RepoLimitExceededErrorModal from "pages/Editor/gitSync/RepoLimitExceededE import { resetEditorRequest } from "actions/initActions"; import { hasCreateNewAppPermission, - hasCreateWorkspacePermission, hasDeleteWorkspacePermission, isPermitted, PERMISSION_TYPE, @@ -100,6 +99,9 @@ import { usePackage } from "@appsmith/pages/Applications/helpers"; import PackageCardList from "@appsmith/pages/Applications/PackageCardList"; import WorkspaceAction from "@appsmith/pages/Applications/WorkspaceAction"; import ResourceListLoader from "@appsmith/pages/Applications/ResourceListLoader"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasCreateWorkspacePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; export const { cloudHosting } = getAppsmithConfigs(); @@ -314,6 +316,7 @@ export function LeftPane(props: LeftPaneProps) { const fetchedUserWorkspaces = useSelector(getUserApplicationsWorkspaces); const isFetchingApplications = useSelector(getIsFetchingApplications); const isMobile = useIsMobileDevice(); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); let userWorkspaces; if (!isFetchingApplications) { @@ -323,7 +326,10 @@ export function LeftPane(props: LeftPaneProps) { } const tenantPermissions = useSelector(getTenantPermissions); - const canCreateWorkspace = hasCreateWorkspacePermission(tenantPermissions); + const canCreateWorkspace = getHasCreateWorkspacePermission( + isFeatureEnabled, + tenantPermissions, + ); const location = useLocation(); const urlHash = location.hash.slice(1); diff --git a/app/client/src/ce/utils/BusinessFeatures/adminSettingsHelpers.tsx b/app/client/src/ce/utils/BusinessFeatures/adminSettingsHelpers.tsx new file mode 100644 index 0000000000..0e548c4caf --- /dev/null +++ b/app/client/src/ce/utils/BusinessFeatures/adminSettingsHelpers.tsx @@ -0,0 +1,30 @@ +import type { User } from "constants/userConstants"; +// eslint-disable-next-line @typescript-eslint/no-restricted-imports +import { showAdminSettings as showAdminSettings_CE } from "ce/utils/adminSettingsHelpers"; +import { showAdminSettings as showAdminSettings_EE } from "@appsmith/utils/adminSettingsHelpers"; + +// eslint-disable-next-line @typescript-eslint/no-restricted-imports +import { getDefaultAdminSettingsPath as getDefaultAdminSettingsPath_CE } from "ce/utils/adminSettingsHelpers"; +import { getDefaultAdminSettingsPath as getDefaultAdminSettingsPath_EE } from "@appsmith/utils/adminSettingsHelpers"; + +export const getShowAdminSettings = ( + isEnabled: boolean, + user: User | undefined, +) => { + if (isEnabled) { + return showAdminSettings_EE(user); + } else { + return showAdminSettings_CE(user); + } +}; +export const getAdminSettingsPath = ( + isEnabled: boolean, + isSuperUser: boolean | undefined, + tenantPermissions: string[] = [], +) => { + if (isEnabled) { + return getDefaultAdminSettingsPath_EE({ isSuperUser, tenantPermissions }); + } else { + return getDefaultAdminSettingsPath_CE({ isSuperUser, tenantPermissions }); + } +}; diff --git a/app/client/src/ce/utils/BusinessFeatures/permissionPageHelpers.tsx b/app/client/src/ce/utils/BusinessFeatures/permissionPageHelpers.tsx new file mode 100644 index 0000000000..1450eeb613 --- /dev/null +++ b/app/client/src/ce/utils/BusinessFeatures/permissionPageHelpers.tsx @@ -0,0 +1,143 @@ +/* eslint-disable @typescript-eslint/no-restricted-imports */ +import { hasCreateWorkspacePermission as hasCreateWorkspacePermission_CE } from "ce/utils/permissionHelpers"; +import { hasCreateWorkspacePermission as hasCreateWorkspacePermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasCreateDatasourcePermission as hasCreateDatasourcePermission_CE } from "ce/utils/permissionHelpers"; +import { hasCreateDatasourcePermission as hasCreateDatasourcePermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasManageDatasourcePermission as hasManageDatasourcePermission_CE } from "ce/utils/permissionHelpers"; +import { hasManageDatasourcePermission as hasManageDatasourcePermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasDeleteDatasourcePermission as hasDeleteDatasourcePermission_CE } from "ce/utils/permissionHelpers"; +import { hasDeleteDatasourcePermission as hasDeleteDatasourcePermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasCreateDatasourceActionPermission as hasCreateDatasourceActionPermission_CE } from "ce/utils/permissionHelpers"; +import { hasCreateDatasourceActionPermission as hasCreateDatasourceActionPermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasCreatePagePermission as hasCreatePagePermission_CE } from "ce/utils/permissionHelpers"; +import { hasCreatePagePermission as hasCreatePagePermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasManagePagePermission as hasManagePagePermission_CE } from "ce/utils/permissionHelpers"; +import { hasManagePagePermission as hasManagePagePermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasDeletePagePermission as hasDeletePagePermission_CE } from "ce/utils/permissionHelpers"; +import { hasDeletePagePermission as hasDeletePagePermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasCreateActionPermission as hasCreateActionPermission_CE } from "ce/utils/permissionHelpers"; +import { hasCreateActionPermission as hasCreateActionPermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasManageActionPermission as hasManageActionPermission_CE } from "ce/utils/permissionHelpers"; +import { hasManageActionPermission as hasManageActionPermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasDeleteActionPermission as hasDeleteActionPermission_CE } from "ce/utils/permissionHelpers"; +import { hasDeleteActionPermission as hasDeleteActionPermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasExecuteActionPermission as hasExecuteActionPermission_CE } from "ce/utils/permissionHelpers"; +import { hasExecuteActionPermission as hasExecuteActionPermission_EE } from "@appsmith/utils/permissionHelpers"; + +import { hasAuditLogsReadPermission as hasAuditLogsReadPermission_CE } from "ce/utils/permissionHelpers"; +import { hasAuditLogsReadPermission as hasAuditLogsReadPermission_EE } from "@appsmith/utils/permissionHelpers"; + +export const getHasCreateWorkspacePermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasCreateWorkspacePermission_EE(permissions); + else return hasCreateWorkspacePermission_CE(permissions); +}; + +export const getHasCreateDatasourcePermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasCreateDatasourcePermission_EE(permissions); + else return hasCreateDatasourcePermission_CE(permissions); +}; + +export const getHasManageDatasourcePermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasManageDatasourcePermission_EE(permissions); + else return hasManageDatasourcePermission_CE(permissions); +}; + +export const getHasDeleteDatasourcePermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasDeleteDatasourcePermission_EE(permissions); + else return hasDeleteDatasourcePermission_CE(permissions); +}; + +export const getHasCreateDatasourceActionPermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasCreateDatasourceActionPermission_EE(permissions); + else return hasCreateDatasourceActionPermission_CE(permissions); +}; + +export const getHasCreatePagePermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasCreatePagePermission_EE(permissions); + else return hasCreatePagePermission_CE(permissions); +}; + +export const getHasManagePagePermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasManagePagePermission_EE(permissions); + else return hasManagePagePermission_CE(permissions); +}; + +export const getHasDeletePagePermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasDeletePagePermission_EE(permissions); + else return hasDeletePagePermission_CE(permissions); +}; + +export const getHasCreateActionPermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasCreateActionPermission_EE(permissions); + else return hasCreateActionPermission_CE(permissions); +}; + +export const getHasManageActionPermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasManageActionPermission_EE(permissions); + else return hasManageActionPermission_CE(permissions); +}; + +export const getHasDeleteActionPermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasDeleteActionPermission_EE(permissions); + else return hasDeleteActionPermission_CE(permissions); +}; + +export const getHasExecuteActionPermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasExecuteActionPermission_EE(permissions); + else return hasExecuteActionPermission_CE(permissions); +}; + +export const getHasAuditLogsReadPermission = ( + isEnabled: boolean, + permissions?: string[], +) => { + if (isEnabled) return hasAuditLogsReadPermission_EE(permissions); + else return hasAuditLogsReadPermission_CE(permissions); +}; diff --git a/app/client/src/ce/utils/adminSettingsHelpers.ts b/app/client/src/ce/utils/adminSettingsHelpers.ts index ea9558eca0..b16a66827b 100644 --- a/app/client/src/ce/utils/adminSettingsHelpers.ts +++ b/app/client/src/ce/utils/adminSettingsHelpers.ts @@ -33,7 +33,7 @@ export const saveAllowed = ( /* get default admin settings path */ export const getDefaultAdminSettingsPath = ( // eslint-disable-next-line @typescript-eslint/no-unused-vars - { isSuperUser, tenantPermissions = [] }: Record, + { isSuperUser, tenantPermissions: any = [] }: Record, ): string => { return ADMIN_SETTINGS_CATEGORY_DEFAULT_PATH; }; diff --git a/app/client/src/ce/utils/planHelpers.ts b/app/client/src/ce/utils/planHelpers.ts index fdd9d8082d..ac4d594af3 100644 --- a/app/client/src/ce/utils/planHelpers.ts +++ b/app/client/src/ce/utils/planHelpers.ts @@ -13,6 +13,10 @@ export const isSAMLEnabled = (featureFlags: FeatureFlags) => { return featureFlags?.license_sso_saml_enabled; }; +export const isGACEnabled = (featureFlags: FeatureFlags) => { + return featureFlags?.license_gac_enabled; +}; + export const isMultipleEnvEnabled = (featureFlags: FeatureFlags) => { return featureFlags?.release_datasource_environments_enabled; }; diff --git a/app/client/src/components/editorComponents/ActionRightPane/index.tsx b/app/client/src/components/editorComponents/ActionRightPane/index.tsx index 2984029fdf..177f3d81a2 100644 --- a/app/client/src/components/editorComponents/ActionRightPane/index.tsx +++ b/app/client/src/components/editorComponents/ActionRightPane/index.tsx @@ -28,7 +28,6 @@ import { getPagePermissions, } from "selectors/editorSelectors"; import { builderURL } from "RouteBuilder"; -import { hasManagePagePermission } from "@appsmith/utils/permissionHelpers"; import DatasourceStructureHeader from "pages/Editor/Explorer/Datasources/DatasourceStructureHeader"; import { DatasourceStructureContainer as DataStructureList, @@ -59,6 +58,9 @@ import { getIsFirstTimeUserOnboardingEnabled } from "selectors/onboardingSelecto import history from "utils/history"; import { SignpostingWalkthroughConfig } from "pages/Editor/FirstTimeUserOnboarding/Utils"; import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasManagePagePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const SCHEMA_GUIDE_GIF = `${ASSETS_CDN_URL}/schema.gif`; @@ -421,7 +423,12 @@ function ActionSidebar({ const pagePermissions = useSelector(getPagePermissions); - const canEditPage = hasManagePagePermission(pagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canEditPage = getHasManagePagePermission( + isFeatureEnabled, + pagePermissions, + ); const showSuggestedWidgets = canEditPage && hasResponse && suggestedWidgets && !!suggestedWidgets.length; diff --git a/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx b/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx index 6427610669..324f3ee950 100644 --- a/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx +++ b/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx @@ -26,15 +26,17 @@ import { PluginType } from "entities/Action"; import { integrationEditorURL } from "RouteBuilder"; import { EntityIcon } from "pages/Editor/Explorer/ExplorerIcons"; import { createNewQueryAction } from "actions/apiPaneActions"; -import { - hasCreateActionPermission, - hasCreateDatasourceActionPermission, - hasCreateDatasourcePermission, -} from "@appsmith/utils/permissionHelpers"; import type { AppState } from "@appsmith/reducers"; import { getCurrentAppWorkspace } from "@appsmith/selectors/workspaceSelectors"; import { importRemixIcon } from "design-system-old"; import AnalyticsUtil from "utils/AnalyticsUtil"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasCreateActionPermission, + getHasCreateDatasourceActionPermission, + getHasCreateDatasourcePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const AddLineIcon = importRemixIcon( () => import("remixicon-react/AddLineIcon"), ); @@ -72,9 +74,15 @@ export const useFilteredFileOperations = (query = "") => { const pagePermissions = useSelector(getPagePermissions); - const canCreateActions = hasCreateActionPermission(pagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const canCreateDatasource = hasCreateDatasourcePermission( + const canCreateActions = getHasCreateActionPermission( + isFeatureEnabled, + pagePermissions, + ); + + const canCreateDatasource = getHasCreateDatasourcePermission( + isFeatureEnabled, userWorkspacePermissions, ); @@ -109,6 +117,7 @@ export const getFilteredAndSortedFileOperations = ( canCreateActions = true, canCreateDatasource = true, pagePermissions: string[] = [], + isFeatureEnabled = false, ) => { const fileOperations: ActionOperation[] = []; if (!canCreateActions) return fileOperations; @@ -118,7 +127,7 @@ export const getFilteredAndSortedFileOperations = ( // Add app datasources if (appWideDS.length > 0 || otherDS.length > 0) { const showCreateQuery = [...appWideDS, ...otherDS].some((ds: Datasource) => - hasCreateDatasourceActionPermission([ + getHasCreateDatasourceActionPermission(isFeatureEnabled, [ ...(ds.userPermissions ?? []), ...pagePermissions, ]), @@ -135,7 +144,7 @@ export const getFilteredAndSortedFileOperations = ( // get all datasources, app ds listed first const datasources = [...appWideDS, ...otherDS].filter((ds) => - hasCreateDatasourceActionPermission([ + getHasCreateDatasourceActionPermission(isFeatureEnabled, [ ...(ds.userPermissions ?? []), ...pagePermissions, ]), diff --git a/app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx b/app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx index 419e3a633e..2d5002db86 100644 --- a/app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx +++ b/app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx @@ -45,10 +45,6 @@ import { } from "@appsmith/selectors/entitiesSelector"; import { extractApiUrlPath } from "transformers/RestActionTransformer"; import { getCurrentAppWorkspace } from "@appsmith/selectors/workspaceSelectors"; -import { - hasCreateDatasourcePermission, - hasManageDatasourcePermission, -} from "@appsmith/utils/permissionHelpers"; import { Text } from "design-system"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; import LazyCodeEditor from "components/editorComponents/LazyCodeEditor"; @@ -58,6 +54,12 @@ import { isEnvironmentValid } from "@appsmith/utils/Environments"; import { DEFAULT_DATASOURCE_NAME } from "constants/ApiEditorConstants/ApiEditorConstants"; import { isString } from "lodash"; import { getCurrentEnvironmentId } from "@appsmith/selectors/environmentSelectors"; +import { + getHasCreateDatasourcePermission, + getHasManageDatasourcePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { isGACEnabled } from "@appsmith/utils/planHelpers"; +import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; type ReduxStateProps = { workspaceId: string; @@ -70,6 +72,7 @@ type ReduxStateProps = { actionName: string; formName: string; userWorkspacePermissions: string[]; + isFeatureEnabled: boolean; }; type ReduxDispatchProps = { @@ -499,6 +502,7 @@ class EmbeddedDatasourcePathComponent extends React.Component< datasource, datasourceObject, input: { value }, + isFeatureEnabled, userWorkspacePermissions, } = this.props; const datasourceUrl = get(datasource, "datasourceConfiguration.url", ""); @@ -508,16 +512,18 @@ class EmbeddedDatasourcePathComponent extends React.Component< value: displayValue, onChange: this.handleOnChange, }; - const shouldSave = datasource && !("id" in datasource); + const isGACFeatureEnabled = isFeatureEnabled; - const canCreateDatasource = hasCreateDatasourcePermission( + const canCreateDatasource = getHasCreateDatasourcePermission( + isGACFeatureEnabled, userWorkspacePermissions, ); const datasourcePermissions = datasourceObject?.userPermissions || []; - const canManageDatasource = hasManageDatasourcePermission( + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); @@ -585,13 +591,20 @@ class EmbeddedDatasourcePathComponent extends React.Component< const mapStateToProps = ( state: AppState, - ownProps: { pluginId: string; actionName: string; formName: string }, + ownProps: { + pluginId: string; + actionName: string; + formName: string; + isFeatureEnabled: boolean; + }, ): ReduxStateProps => { const apiFormValueSelector = formValueSelector(ownProps.formName); const datasourceFromAction = apiFormValueSelector(state, "datasource"); let datasourceMerged = datasourceFromAction || {}; let datasourceFromDataSourceList: Datasource | undefined; const currentEnvironment = getCurrentEnvironmentId(state); + const featureFlags = selectFeatureFlags(state); + const isFeatureEnabled = isGACEnabled(featureFlags); // Todo: fix this properly later in #2164 if (datasourceFromAction && "id" in datasourceFromAction) { datasourceFromDataSourceList = getDatasource( @@ -619,6 +632,7 @@ const mapStateToProps = ( formName: ownProps.formName, userWorkspacePermissions: getCurrentAppWorkspace(state)?.userPermissions ?? [], + isFeatureEnabled: isFeatureEnabled, }; }; diff --git a/app/client/src/ee/utils/BusinessFeatures/adminSettingsHelpers.tsx b/app/client/src/ee/utils/BusinessFeatures/adminSettingsHelpers.tsx new file mode 100644 index 0000000000..6d8ed8559f --- /dev/null +++ b/app/client/src/ee/utils/BusinessFeatures/adminSettingsHelpers.tsx @@ -0,0 +1 @@ +export * from "ce/utils/BusinessFeatures/adminSettingsHelpers"; diff --git a/app/client/src/ee/utils/BusinessFeatures/permissionPageHelpers.tsx b/app/client/src/ee/utils/BusinessFeatures/permissionPageHelpers.tsx new file mode 100644 index 0000000000..22a2bf07a0 --- /dev/null +++ b/app/client/src/ee/utils/BusinessFeatures/permissionPageHelpers.tsx @@ -0,0 +1 @@ +export * from "ce/utils/BusinessFeatures/permissionPageHelpers"; diff --git a/app/client/src/pages/AdminSettings/LeftPane.tsx b/app/client/src/pages/AdminSettings/LeftPane.tsx index f131dbce38..6d00765def 100644 --- a/app/client/src/pages/AdminSettings/LeftPane.tsx +++ b/app/client/src/pages/AdminSettings/LeftPane.tsx @@ -15,12 +15,14 @@ import { getCurrentUser } from "selectors/usersSelectors"; import BusinessTag from "components/BusinessTag"; import EnterpriseTag from "components/EnterpriseTag"; import { getTenantPermissions } from "@appsmith/selectors/tenantSelectors"; -import { hasAuditLogsReadPermission } from "@appsmith/utils/permissionHelpers"; import { getFilteredAclCategories, getFilteredGeneralCategories, getFilteredOtherCategories, } from "@appsmith/utils/adminSettingsHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasAuditLogsReadPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; export const Wrapper = styled.div` flex-basis: ${(props) => props.theme.sidebarWidth}; @@ -190,7 +192,11 @@ export default function LeftPane() { const user = useSelector(getCurrentUser); const isSuperUser = user?.isSuperUser; const tenantPermissions = useSelector(getTenantPermissions); - const isAuditLogsEnabled = hasAuditLogsReadPermission(tenantPermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const isAuditLogsEnabled = getHasAuditLogsReadPermission( + isFeatureEnabled, + tenantPermissions, + ); const filteredGeneralCategories = getFilteredGeneralCategories(categories); diff --git a/app/client/src/pages/AdminSettings/Main.tsx b/app/client/src/pages/AdminSettings/Main.tsx index 499bd579a1..485d245d66 100644 --- a/app/client/src/pages/AdminSettings/Main.tsx +++ b/app/client/src/pages/AdminSettings/Main.tsx @@ -3,13 +3,13 @@ import AdminConfig from "@appsmith/pages/AdminSettings/config"; import { Redirect, useParams } from "react-router"; import { SettingCategories } from "@appsmith/pages/AdminSettings/config/types"; import SettingsForm from "pages/AdminSettings/SettingsForm"; -import { - getDefaultAdminSettingsPath, - getWrapperCategory, -} from "@appsmith/utils/adminSettingsHelpers"; +import { getWrapperCategory } from "@appsmith/utils/adminSettingsHelpers"; import { useSelector } from "react-redux"; import { getCurrentUser } from "selectors/usersSelectors"; import { getTenantPermissions } from "@appsmith/selectors/tenantSelectors"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getAdminSettingsPath } from "@appsmith/utils/BusinessFeatures/adminSettingsHelpers"; const Main = () => { const params = useParams() as any; @@ -22,6 +22,7 @@ const Main = () => { subCategory, category, ); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); if (!!wrapperCategory?.component) { const { component: WrapperCategoryComponent } = wrapperCategory; @@ -32,7 +33,11 @@ const Main = () => { ) { return ( ); } else { diff --git a/app/client/src/pages/Editor/APIEditor/ApiAuthentication.tsx b/app/client/src/pages/Editor/APIEditor/ApiAuthentication.tsx index 9ca2be99d5..887b9716eb 100644 --- a/app/client/src/pages/Editor/APIEditor/ApiAuthentication.tsx +++ b/app/client/src/pages/Editor/APIEditor/ApiAuthentication.tsx @@ -15,12 +15,14 @@ import { } from "@appsmith/constants/messages"; import StoreAsDatasource from "components/editorComponents/StoreAsDatasource"; import { getCurrentAppWorkspace } from "@appsmith/selectors/workspaceSelectors"; -import { - hasCreateDatasourcePermission, - hasManageDatasourcePermission, -} from "@appsmith/utils/permissionHelpers"; import { Icon, Text } from "design-system"; import { getCurrentEnvironmentId } from "@appsmith/selectors/environmentSelectors"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasCreateDatasourcePermission, + getHasManageDatasourcePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; interface ReduxStateProps { datasource: EmbeddedRestDatasource; } @@ -96,13 +98,17 @@ function ApiAuthentication(props: Props): JSX.Element { (state: AppState) => getCurrentAppWorkspace(state)?.userPermissions ?? [], ); - const canCreateDatasource = hasCreateDatasourcePermission( + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateDatasource = getHasCreateDatasourcePermission( + isFeatureEnabled, userWorkspacePermissions, ); const datasourcePermissions = datasource?.userPermissions || []; - const canManageDatasource = hasManageDatasourcePermission( + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); diff --git a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx index 4b893ee375..9d38957309 100644 --- a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx +++ b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx @@ -48,17 +48,19 @@ import equal from "fast-deep-equal/es6"; import ApiAuthentication from "./ApiAuthentication"; import { replayHighlightClass } from "globalStyles/portals"; import { getPlugin } from "@appsmith/selectors/entitiesSelector"; -import { - hasDeleteActionPermission, - hasExecuteActionPermission, - hasManageActionPermission, -} from "@appsmith/utils/permissionHelpers"; import { setApiPaneConfigSelectedTabIndex } from "actions/apiPaneActions"; import type { AutoGeneratedHeader } from "./helpers"; import { showDebuggerFlag } from "selectors/debuggerSelectors"; import { getApiPaneConfigSelectedTabIndex } from "selectors/apiPaneSelectors"; import { noop } from "lodash"; import { DEFAULT_DATASOURCE_NAME } from "constants/ApiEditorConstants/ApiEditorConstants"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasDeleteActionPermission, + getHasExecuteActionPermission, + getHasManageActionPermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const Form = styled.form` position: relative; @@ -531,13 +533,17 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { (action) => action.id === params.apiId || action.id === params.queryId, ); const { pageId } = useParams(); - const isChangePermitted = hasManageActionPermission( + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const isChangePermitted = getHasManageActionPermission( + isFeatureEnabled, currentActionConfig?.userPermissions, ); - const isExecutePermitted = hasExecuteActionPermission( + const isExecutePermitted = getHasExecuteActionPermission( + isFeatureEnabled, currentActionConfig?.userPermissions, ); - const isDeletePermitted = hasDeleteActionPermission( + const isDeletePermitted = getHasDeleteActionPermission( + isFeatureEnabled, currentActionConfig?.userPermissions, ); diff --git a/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx b/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx index a51dd87770..f17c5bc473 100644 --- a/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx +++ b/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx @@ -16,7 +16,6 @@ import { PAGE_SETTINGS_ACTION_NAME_CONFLICT_ERROR, } from "@appsmith/constants/messages"; import type { Page } from "@appsmith/constants/ReduxActionConstants"; -import { hasManagePagePermission } from "@appsmith/utils/permissionHelpers"; import classNames from "classnames"; import { Input, Switch } from "design-system"; import ManualUpgrades from "components/BottomBar/ManualUpgrades"; @@ -35,6 +34,9 @@ import { filterAccentedAndSpecialCharacters, getUrlPreview } from "../Utils"; import type { AppState } from "@appsmith/reducers"; import { getUsedActionNames } from "selectors/actionSelectors"; import { isNameValid, resolveAsSpaceChar } from "utils/helpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasManagePagePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const UrlPreviewWrapper = styled.div` height: 52px; @@ -61,8 +63,10 @@ function PageSettings(props: { page: Page }) { const appNeedsUpdate = applicationVersion < ApplicationVersion.SLUG_URL; + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const [canManagePages, setCanManagePages] = useState( - hasManagePagePermission(page?.userPermissions || []), + getHasManagePagePermission(isFeatureEnabled, page?.userPermissions || []), ); const [pageName, setPageName] = useState(page.pageName); @@ -103,7 +107,9 @@ function PageSettings(props: { page: Page }) { setCustomSlug(page.customSlug || ""); setIsShown(!!!page.isHidden); setIsDefault(!!page.isDefault); - setCanManagePages(hasManagePagePermission(page?.userPermissions || [])); + setCanManagePages( + getHasManagePagePermission(isFeatureEnabled, page?.userPermissions || []), + ); }, [page, page.pageName, page.customSlug, page.isHidden, page.isDefault]); useEffect(() => { @@ -279,7 +285,7 @@ function PageSettings(props: { page: Page }) { )} -
+
-
+
{ const userAppPermissions = useSelector( (state: AppState) => getCurrentApplication(state)?.userPermissions ?? [], ); - const canCreatePages = hasCreatePagePermission(userAppPermissions); - const canCreateDatasourceActions = hasCreateDatasourceActionPermission([ - ...datasourcePermissions, - ...pagePermissions, - ]); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreatePages = getHasCreatePagePermission( + isFeatureEnabled, + userAppPermissions, + ); + + const canCreateDatasourceActions = getHasCreateDatasourceActionPermission( + isFeatureEnabled, + [...datasourcePermissions, ...pagePermissions], + ); const applicationId: string = useSelector(getCurrentApplicationId); const { pageId: currentPageId } = useParams(); diff --git a/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx b/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx index 01297fb456..b77b333cff 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/RestAPIDatasourceForm.tsx @@ -38,8 +38,10 @@ import CopyToClipBoard from "components/designSystems/appsmith/CopyToClipBoard"; import { updateReplayEntity } from "actions/pageActions"; import { ENTITY_TYPE } from "entities/AppsmithConsole"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; -import { hasManageDatasourcePermission } from "@appsmith/utils/permissionHelpers"; import { Form } from "./DBForm"; +import { selectFeatureFlagCheck } from "@appsmith/selectors/featureFlagsSelectors"; +import { getHasManageDatasourcePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; interface DatasourceRestApiEditorProps { initializeReplayEntity: (id: string, data: any) => void; @@ -73,6 +75,7 @@ interface DatasourceRestApiEditorProps { triggerSave?: boolean; datasourceDeleteTrigger: () => void; viewMode: boolean; + isFeatureEnabled: boolean; } type Props = DatasourceRestApiEditorProps & @@ -189,9 +192,10 @@ class DatasourceRestAPIEditor extends React.Component { }; validate = (): boolean => { - const { datasource, datasourceId, formData } = this.props; + const { datasource, datasourceId, formData, isFeatureEnabled } = this.props; const createMode = datasourceId === TEMP_DATASOURCE_ID; - const canManageDatasource = hasManageDatasourcePermission( + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasource?.userPermissions || [], ); if (!formData) return true; @@ -1006,11 +1010,17 @@ const mapStateToProps = (state: AppState, props: any) => { const { currentEnvironment, datasource, formName } = props; const hintMessages = datasource && datasource.messages; + const isFeatureEnabled = selectFeatureFlagCheck( + state, + FEATURE_FLAG.license_gac_enabled, + ); + return { initialValues: datasourceToFormValues(datasource, currentEnvironment), formMeta: getFormMeta(formName)(state), messages: hintMessages, datasourceName: datasource?.name ?? "", + isFeatureEnabled, }; }; diff --git a/app/client/src/pages/Editor/DataSourceEditor/SaveOrDiscardDatasourceModal.tsx b/app/client/src/pages/Editor/DataSourceEditor/SaveOrDiscardDatasourceModal.tsx index e1de9bea0b..c73efadc77 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/SaveOrDiscardDatasourceModal.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/SaveOrDiscardDatasourceModal.tsx @@ -15,7 +15,9 @@ import { Text, } from "design-system"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; -import { hasManageDatasourcePermission } from "@appsmith/utils/permissionHelpers"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { getHasManageDatasourcePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; interface SaveOrDiscardModalProps { isOpen: boolean; @@ -39,7 +41,9 @@ function SaveOrDiscardDatasourceModal(props: SaveOrDiscardModalProps) { } = props; const createMode = datasourceId === TEMP_DATASOURCE_ID; - const canManageDatasources = hasManageDatasourcePermission( + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const canManageDatasources = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); const disableSaveButton = !createMode && !canManageDatasources; diff --git a/app/client/src/pages/Editor/DataSourceEditor/index.tsx b/app/client/src/pages/Editor/DataSourceEditor/index.tsx index 952e7336a9..6633322f3b 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/index.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/index.tsx @@ -59,11 +59,6 @@ import { isDatasourceInViewMode } from "selectors/ui"; import { getQueryParams } from "utils/URLUtils"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; import SaveOrDiscardDatasourceModal from "./SaveOrDiscardDatasourceModal"; -import { - hasCreateDatasourceActionPermission, - hasDeleteDatasourcePermission, - hasManageDatasourcePermission, -} from "@appsmith/utils/permissionHelpers"; import { toast, Callout } from "design-system"; import styled from "styled-components"; @@ -104,6 +99,12 @@ import AnalyticsUtil from "utils/AnalyticsUtil"; import { DATASOURCES_ALLOWED_FOR_PREVIEW_MODE } from "constants/QueryEditorConstants"; import { setCurrentEditingEnvironmentID } from "@appsmith/actions/environmentAction"; import { getCurrentEnvironmentDetails } from "@appsmith/selectors/environmentSelectors"; +import { isGACEnabled } from "@appsmith/utils/planHelpers"; +import { + getHasCreateDatasourceActionPermission, + getHasDeleteDatasourcePermission, + getHasManageDatasourcePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; interface ReduxStateProps { canCreateDatasourceActions: boolean; @@ -1038,19 +1039,24 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => { const datasourcePermissions = datasource?.userPermissions || []; - const canManageDatasource = hasManageDatasourcePermission( + const featureFlags = selectFeatureFlags(state); + const isFeatureEnabled = isGACEnabled(featureFlags); + + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); - const canDeleteDatasource = hasDeleteDatasourcePermission( + const canDeleteDatasource = getHasDeleteDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); const pagePermissions = getPagePermissions(state); - const canCreateDatasourceActions = hasCreateDatasourceActionPermission([ - ...datasourcePermissions, - ...pagePermissions, - ]); + const canCreateDatasourceActions = getHasCreateDatasourceActionPermission( + isFeatureEnabled, + [...datasourcePermissions, ...pagePermissions], + ); // Debugger render flag const showDebugger = showDebuggerFlag(state); const pluginPackageName = plugin?.packageName ?? ""; @@ -1070,8 +1076,6 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => { pluginId, ); - const featureFlags = selectFeatureFlags(state); - // A/B feature flag for datasource view mode preview data. let isEnabledForDSViewModeSchema = selectFeatureFlagCheck( state, diff --git a/app/client/src/pages/Editor/Explorer/Actions/ActionEntity.tsx b/app/client/src/pages/Editor/Explorer/Actions/ActionEntity.tsx index 1bea7199e9..a31039393b 100644 --- a/app/client/src/pages/Editor/Explorer/Actions/ActionEntity.tsx +++ b/app/client/src/pages/Editor/Explorer/Actions/ActionEntity.tsx @@ -19,11 +19,13 @@ import { keyBy } from "lodash"; import { getActionConfig } from "./helpers"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { useLocation } from "react-router"; -import { - hasDeleteActionPermission, - hasManageActionPermission, -} from "@appsmith/utils/permissionHelpers"; import type { Datasource } from "entities/Datasource"; +import { + getHasDeleteActionPermission, + getHasManageActionPermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; const getUpdateActionNameReduxAction = (id: string, name: string) => { return saveActionName({ id, name }); @@ -78,9 +80,17 @@ export const ExplorerActionEntity = memo((props: ExplorerActionEntityProps) => { const actionPermissions = action.userPermissions || []; - const canDeleteAction = hasDeleteActionPermission(actionPermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const canManageAction = hasManageActionPermission(actionPermissions); + const canDeleteAction = getHasDeleteActionPermission( + isFeatureEnabled, + actionPermissions, + ); + + const canManageAction = getHasManageActionPermission( + isFeatureEnabled, + actionPermissions, + ); const contextMenu = ( { (state: AppState) => getCurrentAppWorkspace(state).userPermissions ?? [], ); - const canCreateDatasource = hasCreateDatasourcePermission( + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateDatasource = getHasCreateDatasourcePermission( + isFeatureEnabled, userWorkspacePermissions, ); @@ -100,7 +105,8 @@ const Datasources = React.memo(() => { appWideDS.concat(datasourceSuggestions).map((datasource: Datasource) => { const datasourcePermissions = datasource.userPermissions || []; - const canManageDatasource = hasManageDatasourcePermission( + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); return ( diff --git a/app/client/src/pages/Editor/Explorer/Datasources/DataSourceContextMenu.tsx b/app/client/src/pages/Editor/Explorer/Datasources/DataSourceContextMenu.tsx index c6ab3a8941..956fc7148b 100644 --- a/app/client/src/pages/Editor/Explorer/Datasources/DataSourceContextMenu.tsx +++ b/app/client/src/pages/Editor/Explorer/Datasources/DataSourceContextMenu.tsx @@ -13,15 +13,17 @@ import { createMessage, } from "@appsmith/constants/messages"; import type { AppState } from "@appsmith/reducers"; -import { - hasDeleteDatasourcePermission, - hasManageDatasourcePermission, -} from "@appsmith/utils/permissionHelpers"; import { getDatasource } from "@appsmith/selectors/entitiesSelector"; import type { TreeDropdownOption } from "pages/Editor/Explorer/ContextMenu"; import ContextMenu from "pages/Editor/Explorer/ContextMenu"; import { DatasourceStructureContext } from "./DatasourceStructure"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasDeleteDatasourcePermission, + getHasManageDatasourcePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; export function DataSourceContextMenu(props: { datasourceId: string; @@ -51,13 +53,17 @@ export function DataSourceContextMenu(props: { getDatasource(state, props.datasourceId), ); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const datasourcePermissions = datasource?.userPermissions || []; - const canDeleteDatasource = hasDeleteDatasourcePermission( + const canDeleteDatasource = getHasDeleteDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); - const canManageDatasource = hasManageDatasourcePermission( + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); diff --git a/app/client/src/pages/Editor/Explorer/Datasources/DatasourceStructure.tsx b/app/client/src/pages/Editor/Explorer/Datasources/DatasourceStructure.tsx index 21b6ee16b2..5ecd6fcdf0 100644 --- a/app/client/src/pages/Editor/Explorer/Datasources/DatasourceStructure.tsx +++ b/app/client/src/pages/Editor/Explorer/Datasources/DatasourceStructure.tsx @@ -6,7 +6,6 @@ import DatasourceField from "./DatasourceField"; import type { DatasourceTable } from "entities/Datasource"; import { useCloseMenuOnScroll } from "../hooks"; import { SIDEBAR_ID } from "constants/Explorer"; -import { hasCreateDatasourceActionPermission } from "@appsmith/utils/permissionHelpers"; import { useSelector } from "react-redux"; import type { AppState } from "@appsmith/reducers"; import { getDatasource, getPlugin } from "@appsmith/selectors/entitiesSelector"; @@ -18,6 +17,9 @@ import AnalyticsUtil from "utils/AnalyticsUtil"; import type { Plugin } from "api/PluginApi"; import { omit } from "lodash"; import { Virtuoso } from "react-virtuoso"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasCreateDatasourceActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; export enum DatasourceStructureContext { EXPLORER = "entity-explorer", @@ -67,11 +69,12 @@ const DatasourceStructureItem = memo((props: DatasourceStructureItemProps) => { const datasourcePermissions = datasource?.userPermissions || []; const pagePermissions = useSelector(getPagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const canCreateDatasourceActions = hasCreateDatasourceActionPermission([ - ...datasourcePermissions, - ...pagePermissions, - ]); + const canCreateDatasourceActions = getHasCreateDatasourceActionPermission( + isFeatureEnabled, + [...datasourcePermissions, ...pagePermissions], + ); const onSelect = () => { setActive(false); diff --git a/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx b/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx index 887255ecab..1cc3f4202c 100644 --- a/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx +++ b/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx @@ -14,7 +14,7 @@ import { mockDatasources } from "./mockTestData"; import { updateCurrentPage } from "actions/pageActions"; import urlBuilder from "entities/URLRedirect/URLAssembly"; import * as helpers from "@appsmith/pages/Editor/Explorer/helpers"; -import * as permissionUtils from "@appsmith/utils/permissionHelpers"; +import * as permissionPageHelpers from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; import userEvent from "@testing-library/user-event"; import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; import * as widgetSelectionsActions from "actions/widgetSelectionActions"; @@ -40,6 +40,13 @@ jest.mock("@appsmith/pages/Editor/Explorer/helpers", () => ({ ...jest.requireActual("@appsmith/pages/Editor/Explorer/helpers"), })); +jest.mock("@appsmith/utils/BusinessFeatures/permissionPageHelpers", () => ({ + __esModule: true, + ...jest.requireActual( + "@appsmith/utils/BusinessFeatures/permissionPageHelpers", + ), +})); + describe("Entity Explorer tests", () => { beforeAll(() => { runSagaMiddleware(); @@ -69,7 +76,7 @@ describe("Entity Explorer tests", () => { payload: mockDatasources, }); jest - .spyOn(permissionUtils, "hasCreateDatasourcePermission") + .spyOn(permissionPageHelpers, "getHasCreateDatasourcePermission") .mockReturnValue(true); store.dispatch(updateCurrentPage("pageId")); const component = render(); @@ -83,7 +90,7 @@ describe("Entity Explorer tests", () => { payload: mockDatasources, }); jest - .spyOn(permissionUtils, "hasCreateDatasourcePermission") + .spyOn(permissionPageHelpers, "getHasCreateDatasourcePermission") .mockReturnValue(false); const mockExplorerState = jest.spyOn(helpers, "getExplorerStatus"); mockExplorerState.mockImplementationOnce(() => true); @@ -103,13 +110,13 @@ describe("Entity Explorer tests", () => { payload: mockDatasources, }); jest - .spyOn(permissionUtils, "hasCreateDatasourcePermission") + .spyOn(permissionPageHelpers, "getHasCreateDatasourcePermission") .mockReturnValue(true); jest - .spyOn(permissionUtils, "hasManageDatasourcePermission") + .spyOn(permissionPageHelpers, "getHasManageDatasourcePermission") .mockReturnValue(false); jest - .spyOn(permissionUtils, "hasDeleteDatasourcePermission") + .spyOn(permissionPageHelpers, "getHasDeleteDatasourcePermission") .mockReturnValue(false); const mockExplorerState = jest.spyOn(helpers, "getExplorerStatus"); mockExplorerState.mockImplementationOnce(() => true); diff --git a/app/client/src/pages/Editor/Explorer/Files/Submenu.tsx b/app/client/src/pages/Editor/Explorer/Files/Submenu.tsx index bb9fda253f..5eec0a7d87 100644 --- a/app/client/src/pages/Editor/Explorer/Files/Submenu.tsx +++ b/app/client/src/pages/Editor/Explorer/Files/Submenu.tsx @@ -22,7 +22,6 @@ import { } from "@appsmith/constants/messages"; import { useCloseMenuOnScroll } from "../hooks"; import { SIDEBAR_ID } from "constants/Explorer"; -import { hasCreateActionPermission } from "@appsmith/utils/permissionHelpers"; import { Menu, MenuContent, @@ -33,6 +32,9 @@ import { Text, } from "design-system"; import { DatasourceCreateEntryPoints } from "constants/Datasource"; +import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; const SubMenuContainer = styled.div` width: 250px; @@ -73,7 +75,12 @@ export default function ExplorerSubMenu({ const pagePermissions = useSelector(getPagePermissions); - const canCreateActions = hasCreateActionPermission(pagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateActions = getHasCreateActionPermission( + isFeatureEnabled, + pagePermissions, + ); useEffect(() => { setQuery(""); @@ -173,7 +180,7 @@ export default function ExplorerSubMenu({ key={`file-op-${idx}`} onClick={() => handleClick(item)} > -
+
{icon && {icon}} {item.shortTitle || item.title} diff --git a/app/client/src/pages/Editor/Explorer/Files/index.tsx b/app/client/src/pages/Editor/Explorer/Files/index.tsx index 09b225c986..9ab0f2a651 100644 --- a/app/client/src/pages/Editor/Explorer/Files/index.tsx +++ b/app/client/src/pages/Editor/Explorer/Files/index.tsx @@ -22,9 +22,11 @@ import { } from "@appsmith/pages/Editor/Explorer/helpers"; import { AddEntity, EmptyComponent } from "../common"; import ExplorerSubMenu from "./Submenu"; -import { hasCreateActionPermission } from "@appsmith/utils/permissionHelpers"; import { Icon, Text } from "design-system"; import styled from "styled-components"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const StyledText = styled(Text)` color: var(--ads-v2-color-fg-emphasis); @@ -63,7 +65,12 @@ function Files() { const pagePermissions = useSelector(getPagePermissions); - const canCreateActions = hasCreateActionPermission(pagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateActions = getHasCreateActionPermission( + isFeatureEnabled, + pagePermissions, + ); const onMenuClose = useCallback(() => openMenu(false), [openMenu]); diff --git a/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx b/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx index 4e56ecbef4..ea3e880202 100644 --- a/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx +++ b/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx @@ -14,9 +14,11 @@ import { jsCollectionIdURL } from "RouteBuilder"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { useLocation } from "react-router"; import { - hasDeleteActionPermission, - hasManageActionPermission, -} from "@appsmith/utils/permissionHelpers"; + getHasDeleteActionPermission, + getHasManageActionPermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; type ExplorerJSCollectionEntityProps = { step: number; @@ -58,9 +60,17 @@ export const ExplorerJSCollectionEntity = memo( const jsActionPermissions = jsAction.userPermissions || []; - const canDeleteJSAction = hasDeleteActionPermission(jsActionPermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const canManageJSAction = hasManageActionPermission(jsActionPermissions); + const canDeleteJSAction = getHasDeleteActionPermission( + isFeatureEnabled, + jsActionPermissions, + ); + + const canManageJSAction = getHasManageActionPermission( + isFeatureEnabled, + jsActionPermissions, + ); const contextMenu = ( { acc[lib.url] = lib.docsURL; @@ -241,7 +243,7 @@ function LibraryEntity({ lib }: { lib: TJSLibrary }) { name="right-arrow-2" size={"md"} /> -
+
{lib.name} {docsURL && (
@@ -262,7 +264,7 @@ function LibraryEntity({ lib }: { lib: TJSLibrary }) {
-
+
Available as{" "}
{lib.accessor[lib.accessor.length - 1]}{" "} @@ -300,7 +302,12 @@ function JSDependencies() { const pagePermissions = useSelector(getPagePermissions); - const canCreateActions = hasCreateActionPermission(pagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateActions = getHasCreateActionPermission( + isFeatureEnabled, + pagePermissions, + ); const isAirgappedInstance = isAirgapped(); diff --git a/app/client/src/pages/Editor/Explorer/Pages/PageContextMenu.tsx b/app/client/src/pages/Editor/Explorer/Pages/PageContextMenu.tsx index 6262ef8dfc..5883363031 100644 --- a/app/client/src/pages/Editor/Explorer/Pages/PageContextMenu.tsx +++ b/app/client/src/pages/Editor/Explorer/Pages/PageContextMenu.tsx @@ -22,16 +22,18 @@ import { } from "@appsmith/constants/messages"; import { openAppSettingsPaneAction } from "actions/appSettingsPaneActions"; import { AppSettingsTabs } from "pages/Editor/AppSettingsPane/AppSettings"; -import { - hasCreatePagePermission, - hasDeletePagePermission, - hasManagePagePermission, -} from "@appsmith/utils/permissionHelpers"; import { getPageById } from "selectors/editorSelectors"; import { getCurrentApplication } from "@appsmith/selectors/applicationSelectors"; import type { AppState } from "@appsmith/reducers"; import ContextMenu from "pages/Editor/Explorer/ContextMenu"; import type { TreeDropdownOption } from "pages/Editor/Explorer/ContextMenu"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasCreatePagePermission, + getHasDeletePagePermission, + getHasManagePagePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const CustomLabel = styled.div` display: flex; @@ -123,11 +125,22 @@ export function PageContextMenu(props: { (state: AppState) => getCurrentApplication(state)?.userPermissions ?? [], ); - const canCreatePages = hasCreatePagePermission(userAppPermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const canManagePages = hasManagePagePermission(pagePermissions); + const canCreatePages = getHasCreatePagePermission( + isFeatureEnabled, + userAppPermissions, + ); - const canDeletePages = hasDeletePagePermission(pagePermissions); + const canManagePages = getHasManagePagePermission( + isFeatureEnabled, + pagePermissions, + ); + + const canDeletePages = getHasDeletePagePermission( + isFeatureEnabled, + pagePermissions, + ); const optionsTree = [ canManagePages && { diff --git a/app/client/src/pages/Editor/Explorer/Pages/index.tsx b/app/client/src/pages/Editor/Explorer/Pages/index.tsx index c597c934ff..65df2d0d5d 100644 --- a/app/client/src/pages/Editor/Explorer/Pages/index.tsx +++ b/app/client/src/pages/Editor/Explorer/Pages/index.tsx @@ -36,13 +36,15 @@ import AddPageContextMenu from "./AddPageContextMenu"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { useLocation } from "react-router"; import { toggleInOnboardingWidgetSelection } from "actions/onboardingActions"; -import { - hasCreatePagePermission, - hasManagePagePermission, -} from "@appsmith/utils/permissionHelpers"; import type { AppState } from "@appsmith/reducers"; import { getCurrentWorkspaceId } from "@appsmith/selectors/workspaceSelectors"; import { getInstanceId } from "@appsmith//selectors/tenantSelectors"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasCreatePagePermission, + getHasManagePagePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const ENTITY_HEIGHT = 36; const MIN_PAGES_HEIGHT = 60; @@ -172,7 +174,12 @@ function Pages() { (state: AppState) => getCurrentApplication(state)?.userPermissions ?? [], ); - const canCreatePages = hasCreatePagePermission(userAppPermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreatePages = getHasCreatePagePermission( + isFeatureEnabled, + userAppPermissions, + ); const pageElements = useMemo( () => @@ -180,7 +187,10 @@ function Pages() { const icon = page.isDefault ? defaultPageIcon : pageIcon; const isCurrentPage = currentPageId === page.pageId; const pagePermissions = page.userPermissions; - const canManagePages = hasManagePagePermission(pagePermissions); + const canManagePages = getHasManagePagePermission( + isFeatureEnabled, + pagePermissions, + ); const contextMenu = ( { const pagePermissions = useSelector(getPagePermissions); - const canManagePages = hasManagePagePermission(pagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canManagePages = getHasManagePagePermission( + isFeatureEnabled, + pagePermissions, + ); const { isWidgetSelected, diff --git a/app/client/src/pages/Editor/Explorer/Widgets/WidgetGroup.tsx b/app/client/src/pages/Editor/Explorer/Widgets/WidgetGroup.tsx index 277daa19f3..c9c4a82353 100644 --- a/app/client/src/pages/Editor/Explorer/Widgets/WidgetGroup.tsx +++ b/app/client/src/pages/Editor/Explorer/Widgets/WidgetGroup.tsx @@ -22,8 +22,10 @@ import { } from "@appsmith/pages/Editor/Explorer/helpers"; import { AddEntity, EmptyComponent } from "../common"; import { noop } from "lodash"; -import { hasManagePagePermission } from "@appsmith/utils/permissionHelpers"; import { Icon } from "design-system"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasManagePagePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; type ExplorerWidgetGroupProps = { step: number; @@ -58,7 +60,12 @@ export const ExplorerWidgetGroup = memo((props: ExplorerWidgetGroupProps) => { const pagePermissions = useSelector(getPagePermissions); - const canManagePages = hasManagePagePermission(pagePermissions); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canManagePages = getHasManagePagePermission( + isFeatureEnabled, + pagePermissions, + ); return ( getCurrentAppWorkspace(state).userPermissions ?? [], ); - const canCreateDatasource = hasCreateDatasourcePermission( + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateDatasource = getHasCreateDatasourcePermission( + isFeatureEnabled, userWorkspacePermissions, ); diff --git a/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx b/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx index e308767d52..9ed3ccb628 100644 --- a/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx +++ b/app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx @@ -37,12 +37,6 @@ import { getCurrentPageId, getPagePermissions, } from "selectors/editorSelectors"; -import { - hasCreateDatasourceActionPermission, - hasCreatePagePermission, - hasDeleteDatasourcePermission, - hasManageDatasourcePermission, -} from "@appsmith/utils/permissionHelpers"; import { getAssetUrl } from "@appsmith/utils/airgapHelpers"; import { MenuWrapper, StyledMenu } from "components/utils/formComponents"; import { DatasourceEditEntryPoints } from "constants/Datasource"; @@ -53,6 +47,14 @@ import { } from "@appsmith/utils/Environments"; import { getCurrentApplication } from "@appsmith/selectors/applicationSelectors"; import { getCurrentEnvironmentId } from "@appsmith/selectors/environmentSelectors"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasCreateDatasourceActionPermission, + getHasCreatePagePermission, + getHasDeleteDatasourcePermission, + getHasManageDatasourcePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const Wrapper = styled.div` padding: 15px; @@ -167,18 +169,26 @@ function DatasourceCard(props: DatasourceCardProps) { const userAppPermissions = useSelector( (state: AppState) => getCurrentApplication(state)?.userPermissions ?? [], ); - const canCreatePages = hasCreatePagePermission(userAppPermissions); - const canCreateDatasourceActions = hasCreateDatasourceActionPermission([ - ...datasourcePermissions, - ...pagePermissions, - ]); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const canEditDatasource = hasManageDatasourcePermission( + const canCreatePages = getHasCreatePagePermission( + isFeatureEnabled, + userAppPermissions, + ); + + const canCreateDatasourceActions = getHasCreateDatasourceActionPermission( + isFeatureEnabled, + [...datasourcePermissions, ...pagePermissions], + ); + + const canEditDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); - const canDeleteDatasource = hasDeleteDatasourcePermission( + const canDeleteDatasource = getHasDeleteDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); diff --git a/app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx b/app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx index de30120d40..886f9878ee 100644 --- a/app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx +++ b/app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx @@ -28,7 +28,6 @@ import { getCurrentApplicationId } from "selectors/editorSelectors"; import { integrationEditorURL } from "RouteBuilder"; import { getCurrentAppWorkspace } from "@appsmith/selectors/workspaceSelectors"; -import { hasCreateDatasourcePermission } from "@appsmith/utils/permissionHelpers"; import { Tab, TabPanel, Tabs, TabsList } from "design-system"; import Debugger, { ResizerContentContainer, @@ -38,6 +37,9 @@ import { showDebuggerFlag } from "selectors/debuggerSelectors"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { DatasourceCreateEntryPoints } from "constants/Datasource"; import { isAirgapped } from "@appsmith/utils/airgapHelpers"; +import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; +import { isGACEnabled } from "@appsmith/utils/planHelpers"; +import { getHasCreateDatasourcePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const HeaderFlex = styled.div` font-size: 20px; @@ -591,7 +593,11 @@ const mapStateToProps = (state: AppState) => { const userWorkspacePermissions = getCurrentAppWorkspace(state).userPermissions ?? []; - const canCreateDatasource = hasCreateDatasourcePermission( + const featureFlags = selectFeatureFlags(state); + const isFeatureEnabled = isGACEnabled(featureFlags); + + const canCreateDatasource = getHasCreateDatasourcePermission( + isFeatureEnabled, userWorkspacePermissions, ); return { diff --git a/app/client/src/pages/Editor/JSEditor/Form.tsx b/app/client/src/pages/Editor/JSEditor/Form.tsx index 9048f68087..eb5674b906 100644 --- a/app/client/src/pages/Editor/JSEditor/Form.tsx +++ b/app/client/src/pages/Editor/JSEditor/Form.tsx @@ -53,11 +53,6 @@ import { } from "./styledComponents"; import { getJSPaneConfigSelectedTab } from "selectors/jsPaneSelectors"; import type { EventLocation } from "@appsmith/utils/analyticsUtilTypes"; -import { - hasDeleteActionPermission, - hasExecuteActionPermission, - hasManageActionPermission, -} from "@appsmith/utils/permissionHelpers"; import { setCodeEditorCursorAction, setFocusableInputField, @@ -69,6 +64,13 @@ import styled from "styled-components"; import { showDebuggerFlag } from "selectors/debuggerSelectors"; import { Tab, TabPanel, Tabs, TabsList } from "design-system"; import { JSEditorTab } from "reducers/uiReducers/jsPaneReducer"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasDeleteActionPermission, + getHasExecuteActionPermission, + getHasManageActionPermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; interface JSFormProps { jsCollection: JSCollection; @@ -162,13 +164,18 @@ function JSEditorForm({ jsCollection: currentJSCollection }: Props) { } }, [hash]); - const isChangePermitted = hasManageActionPermission( + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const isChangePermitted = getHasManageActionPermission( + isFeatureEnabled, currentJSCollection?.userPermissions || [], ); - const isExecutePermitted = hasExecuteActionPermission( + const isExecutePermitted = getHasExecuteActionPermission( + isFeatureEnabled, currentJSCollection?.userPermissions || [], ); - const isDeletePermitted = hasDeleteActionPermission( + const isDeletePermitted = getHasDeleteActionPermission( + isFeatureEnabled, currentJSCollection?.userPermissions || [], ); diff --git a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx index fe60fc9a10..6433a5f133 100644 --- a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx +++ b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @@ -99,12 +99,6 @@ import { ResponseTabErrorDefaultMessage, } from "components/editorComponents/ApiResponseView"; import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; -import { - hasCreateDatasourcePermission, - hasDeleteActionPermission, - hasExecuteActionPermission, - hasManageActionPermission, -} from "@appsmith/utils/permissionHelpers"; import { getQueryPaneConfigSelectedTabIndex } from "selectors/queryPaneSelectors"; import { setQueryPaneConfigSelectedTabIndex } from "actions/queryPaneActions"; import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; @@ -136,6 +130,14 @@ import { editorSQLModes } from "components/editorComponents/CodeEditor/sql/confi import { EditorFormSignPosting } from "@appsmith/components/editorComponents/EditorFormSignPosting"; import { DatasourceStructureContext } from "../Explorer/Datasources/DatasourceStructure"; import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; +import { + getHasCreateDatasourcePermission, + getHasDeleteActionPermission, + getHasExecuteActionPermission, + getHasManageActionPermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; const QueryFormContainer = styled.form` flex: 1; @@ -420,13 +422,19 @@ export function EditorJSONtoForm(props: Props) { (action) => action.id === params.apiId || action.id === params.queryId, ); const { pageId } = useParams(); - const isChangePermitted = hasManageActionPermission( + + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const isChangePermitted = getHasManageActionPermission( + isFeatureEnabled, currentActionConfig?.userPermissions, ); - const isExecutePermitted = hasExecuteActionPermission( + const isExecutePermitted = getHasExecuteActionPermission( + isFeatureEnabled, currentActionConfig?.userPermissions, ); - const isDeletePermitted = hasDeleteActionPermission( + const isDeletePermitted = getHasDeleteActionPermission( + isFeatureEnabled, currentActionConfig?.userPermissions, ); @@ -434,7 +442,8 @@ export function EditorJSONtoForm(props: Props) { (state: AppState) => getCurrentAppWorkspace(state).userPermissions ?? [], ); - const canCreateDatasource = hasCreateDatasourcePermission( + const canCreateDatasource = getHasCreateDatasourcePermission( + isFeatureEnabled, userWorkspacePermissions, ); diff --git a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx index 3db88f144f..0b08e25d83 100644 --- a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx +++ b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @@ -45,11 +45,6 @@ import { import type { PluginType } from "entities/Action"; import AuthMessage from "pages/common/datasourceAuth/AuthMessage"; import { isDatasourceInViewMode } from "selectors/ui"; -import { - hasCreateDatasourceActionPermission, - hasDeleteDatasourcePermission, - hasManageDatasourcePermission, -} from "@appsmith/utils/permissionHelpers"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; import { createTempDatasourceFromForm, @@ -87,6 +82,13 @@ import GoogleSheetSchema from "./GoogleSheetSchema"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { getDefaultEnvironmentId } from "@appsmith/selectors/environmentSelectors"; import { DEFAULT_ENV_ID } from "@appsmith/api/ApiUtils"; +import { + getHasCreateDatasourceActionPermission, + getHasDeleteDatasourcePermission, + getHasManageDatasourcePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { selectFeatureFlagCheck } from "@appsmith/selectors/featureFlagsSelectors"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; const ViewModeContainer = styled.div` display: flex; @@ -707,19 +709,26 @@ const mapStateToProps = (state: AppState, props: any) => { const datasourcePermissions = datasource?.userPermissions || []; - const canManageDatasource = hasManageDatasourcePermission( + const isFeatureEnabled = selectFeatureFlagCheck( + state, + FEATURE_FLAG.license_gac_enabled, + ); + + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); - const canDeleteDatasource = hasDeleteDatasourcePermission( + const canDeleteDatasource = getHasDeleteDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); const pagePermissions = getPagePermissions(state); - const canCreateDatasourceActions = hasCreateDatasourceActionPermission([ - ...datasourcePermissions, - ...pagePermissions, - ]); + const canCreateDatasourceActions = getHasCreateDatasourceActionPermission( + isFeatureEnabled, + [...datasourcePermissions, ...pagePermissions], + ); const gsheetToken = getGsheetToken(state); const gsheetProjectID = getGsheetProjectID(state); diff --git a/app/client/src/pages/Editor/SaaSEditor/GoogleSheetSchema.tsx b/app/client/src/pages/Editor/SaaSEditor/GoogleSheetSchema.tsx index a1ef435584..d6feb5155c 100644 --- a/app/client/src/pages/Editor/SaaSEditor/GoogleSheetSchema.tsx +++ b/app/client/src/pages/Editor/SaaSEditor/GoogleSheetSchema.tsx @@ -32,13 +32,15 @@ import { GSHEETS_SCHEMA_NO_DATA, } from "@appsmith/constants/messages"; import AnalyticsUtil from "utils/AnalyticsUtil"; -import { - hasCreateDatasourceActionPermission, - hasCreatePagePermission, -} from "@appsmith/utils/permissionHelpers"; import { getCurrentApplication } from "@appsmith/selectors/applicationSelectors"; import type { AppState } from "@appsmith/reducers"; import { getDatasource } from "@appsmith/selectors/entitiesSelector"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getHasCreateDatasourceActionPermission, + getHasCreatePagePermission, +} from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; export const MessageWrapper = styled.div` display: flex; @@ -287,12 +289,18 @@ function GoogleSheetSchema(props: Props) { const userAppPermissions = useSelector( (state: AppState) => getCurrentApplication(state)?.userPermissions ?? [], ); - const canCreatePages = hasCreatePagePermission(userAppPermissions); - const canCreateDatasourceActions = hasCreateDatasourceActionPermission([ - ...datasourcePermissions, - ...pagePermissions, - ]); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreatePages = getHasCreatePagePermission( + isFeatureEnabled, + userAppPermissions, + ); + + const canCreateDatasourceActions = getHasCreateDatasourceActionPermission( + isFeatureEnabled, + [...datasourcePermissions, ...pagePermissions], + ); const showGeneratePageBtn = !isLoading && diff --git a/app/client/src/pages/Home/LeftPaneBottomSection.tsx b/app/client/src/pages/Home/LeftPaneBottomSection.tsx index 9581bb60b3..9676e97f16 100644 --- a/app/client/src/pages/Home/LeftPaneBottomSection.tsx +++ b/app/client/src/pages/Home/LeftPaneBottomSection.tsx @@ -21,14 +21,16 @@ import { getOnSelectAction, } from "pages/common/CustomizedDropdown/dropdownHelpers"; import { getCurrentUser } from "selectors/usersSelectors"; -import { - getDefaultAdminSettingsPath, - showAdminSettings, -} from "@appsmith/utils/adminSettingsHelpers"; import { getTenantPermissions } from "@appsmith/selectors/tenantSelectors"; import { isAirgapped } from "@appsmith/utils/airgapHelpers"; import { ShowUpgradeMenuItem } from "@appsmith/utils/licenseHelpers"; import { DISCORD_URL, DOCS_BASE_URL } from "constants/ThirdPartyConstants"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { + getAdminSettingsPath, + getShowAdminSettings, +} from "@appsmith/utils/BusinessFeatures/adminSettingsHelpers"; export const Wrapper = styled.div` background-color: var(--ads-v2-color-bg); @@ -84,26 +86,29 @@ function LeftPaneBottomSection() { const [isProductUpdatesModalOpen, setIsProductUpdatesModalOpen] = useState(false); const isAirgappedInstance = isAirgapped(); + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); return ( - {showAdminSettings(user) && !isFetchingApplications && ( - { - getOnSelectAction(DropdownOnSelectActions.REDIRECT, { - path: getDefaultAdminSettingsPath({ - isSuperUser: user?.isSuperUser, - tenantPermissions, - }), - }); - }} - text={createMessage(ADMIN_SETTINGS)} - /> - )} + {getShowAdminSettings(isFeatureEnabled, user) && + !isFetchingApplications && ( + { + getOnSelectAction(DropdownOnSelectActions.REDIRECT, { + path: getAdminSettingsPath( + isFeatureEnabled, + user?.isSuperUser, + tenantPermissions, + ), + }); + }} + text={createMessage(ADMIN_SETTINGS)} + /> + )} {!isAirgappedInstance && ( <> @@ -110,10 +113,11 @@ export default function MobileSideBar(props: MobileSideBarProps) { icon="setting" onSelect={() => { getOnSelectAction(DropdownOnSelectActions.REDIRECT, { - path: getDefaultAdminSettingsPath({ - isSuperUser: user?.isSuperUser, + path: getAdminSettingsPath( + isFeatureEnabled, + user?.isSuperUser, tenantPermissions, - }), + ), }); }} text={createMessage(ADMIN_SETTINGS)} diff --git a/app/client/src/pages/common/datasourceAuth/index.tsx b/app/client/src/pages/common/datasourceAuth/index.tsx index d088807714..04d26e0ada 100644 --- a/app/client/src/pages/common/datasourceAuth/index.tsx +++ b/app/client/src/pages/common/datasourceAuth/index.tsx @@ -29,14 +29,15 @@ import { import { Button, toast } from "design-system"; import type { ApiDatasourceForm } from "entities/Datasource/RestAPIForm"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; - -import { hasManageDatasourcePermission } from "@appsmith/utils/permissionHelpers"; import { INTEGRATION_TABS, SHOW_FILE_PICKER_KEY } from "constants/routes"; import { integrationEditorURL } from "RouteBuilder"; import { getQueryParams } from "utils/URLUtils"; import type { AppsmithLocationState } from "utils/history"; import type { PluginType } from "entities/Action"; import { getCurrentEnvironmentDetails } from "@appsmith/selectors/environmentSelectors"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasManageDatasourcePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; interface Props { datasource: Datasource; @@ -161,7 +162,10 @@ function DatasourceAuth({ const datasourcePermissions = datasource.userPermissions || []; - const canManageDatasource = hasManageDatasourcePermission( + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canManageDatasource = getHasManageDatasourcePermission( + isFeatureEnabled, datasourcePermissions, ); diff --git a/app/client/src/sagas/ApiPaneSagas.ts b/app/client/src/sagas/ApiPaneSagas.ts index 35e1bea29a..9ee5664afd 100644 --- a/app/client/src/sagas/ApiPaneSagas.ts +++ b/app/client/src/sagas/ApiPaneSagas.ts @@ -78,7 +78,6 @@ import { } from "RouteBuilder"; import { getCurrentPageId } from "selectors/editorSelectors"; import { validateResponse } from "./ErrorSagas"; -import { hasManageActionPermission } from "@appsmith/utils/permissionHelpers"; import type { CreateDatasourceSuccessAction } from "actions/datasourceActions"; import { removeTempDatasource } from "actions/datasourceActions"; import { klona } from "klona/lite"; @@ -86,6 +85,10 @@ import { toast } from "design-system"; import type { AutoGeneratedHeader } from "pages/Editor/APIEditor/helpers"; import { deriveAutoGeneratedHeaderState } from "pages/Editor/APIEditor/helpers"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; +import type { FeatureFlags } from "@appsmith/entities/FeatureFlag"; +import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; +import { isGACEnabled } from "@appsmith/utils/planHelpers"; +import { getHasManageActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; function* syncApiParamsSaga( actionPayload: ReduxActionWithMeta, @@ -393,8 +396,14 @@ function* formValueChangeSaga( if (form !== API_EDITOR_FORM_NAME) return; if (field === "dynamicBindingPathList" || field === "name") return; const { values } = yield select(getFormData, API_EDITOR_FORM_NAME); + const featureFlags: FeatureFlags = yield select(selectFeatureFlags); + const isFeatureEnabled = isGACEnabled(featureFlags); + if (!values.id) return; - if (!hasManageActionPermission(values.userPermissions)) { + + if ( + !getHasManageActionPermission(isFeatureEnabled, values.userPermissions) + ) { yield validateResponse({ status: 403, resourceType: values?.pluginType, diff --git a/app/client/src/sagas/PageSagas.tsx b/app/client/src/sagas/PageSagas.tsx index 6f1f712064..363d4aca8e 100644 --- a/app/client/src/sagas/PageSagas.tsx +++ b/app/client/src/sagas/PageSagas.tsx @@ -128,7 +128,6 @@ import WidgetFactory from "WidgetProvider/factory"; import { toggleShowDeviationDialog } from "actions/onboardingActions"; import { builderURL } from "RouteBuilder"; import { failFastApiCalls, waitForWidgetConfigBuild } from "./InitSagas"; -import { hasManagePagePermission } from "@appsmith/utils/permissionHelpers"; import { resizePublishedMainCanvasToLowestWidget } from "./WidgetOperationUtils"; import { checkAndLogErrorsIfCyclicDependency } from "./helper"; import { LOCAL_STORAGE_KEYS } from "utils/localStorage"; @@ -147,6 +146,10 @@ import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; import type { WidgetProps } from "widgets/BaseWidget"; import { nestDSL, flattenDSL } from "@shared/dsl"; import { fetchSnapshotDetailsAction } from "actions/autoLayoutActions"; +import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; +import type { FeatureFlags } from "@appsmith/entities/FeatureFlag"; +import { isGACEnabled } from "@appsmith/utils/planHelpers"; +import { getHasManagePagePermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; const WidgetTypes = WidgetFactory.widgetTypes; @@ -667,8 +670,14 @@ export function* saveLayoutSaga(action: ReduxAction<{ isRetry?: boolean }>) { const appMode: APP_MODE | undefined = yield select(getAppMode); + const featureFlags: FeatureFlags = yield select(selectFeatureFlags); + const isFeatureEnabled = isGACEnabled(featureFlags); + if ( - !hasManagePagePermission(currentPage?.userPermissions || []) && + !getHasManagePagePermission( + isFeatureEnabled, + currentPage?.userPermissions || [], + ) && appMode === APP_MODE.EDIT ) { yield validateResponse({ diff --git a/app/client/src/sagas/QueryPaneSagas.ts b/app/client/src/sagas/QueryPaneSagas.ts index 46ff9f213b..66f78bf805 100644 --- a/app/client/src/sagas/QueryPaneSagas.ts +++ b/app/client/src/sagas/QueryPaneSagas.ts @@ -76,13 +76,16 @@ import { FormDataPaths } from "workers/Evaluation/formEval"; import { fetchDynamicValuesSaga } from "./FormEvaluationSaga"; import type { FormEvalOutput } from "reducers/evaluationReducers/formEvaluationReducer"; import { validateResponse } from "./ErrorSagas"; -import { hasManageActionPermission } from "@appsmith/utils/permissionHelpers"; import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil"; import { toast } from "design-system"; import type { CreateDatasourceSuccessAction } from "actions/datasourceActions"; import { createDefaultActionPayload } from "./ActionSagas"; import { DB_NOT_SUPPORTED } from "@appsmith/utils/Environments"; import { getCurrentEnvironmentId } from "@appsmith/selectors/environmentSelectors"; +import type { FeatureFlags } from "@appsmith/entities/FeatureFlag"; +import { selectFeatureFlags } from "@appsmith/selectors/featureFlagsSelectors"; +import { isGACEnabled } from "@appsmith/utils/planHelpers"; +import { getHasManageActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; // Called whenever the query being edited is changed via the URL or query pane function* changeQuerySaga(actionPayload: ReduxAction<{ id: string }>) { @@ -175,7 +178,12 @@ function* formValueChangeSaga( const { values } = yield select(getFormData, QUERY_EDITOR_FORM_NAME); const hasRouteChanged = field === "id"; - if (!hasManageActionPermission(values.userPermissions)) { + const featureFlags: FeatureFlags = yield select(selectFeatureFlags); + const isFeatureEnabled = isGACEnabled(featureFlags); + + if ( + !getHasManageActionPermission(isFeatureEnabled, values.userPermissions) + ) { yield validateResponse({ status: 403, resourceType: values?.pluginType,