From d036064beb1861828cf2f66b83959d4e41e30e46 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Tue, 13 May 2025 17:36:58 +0530 Subject: [PATCH] chore: Update flags for self-hosting agents (#40639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /ok-to-test tags="@tag.Sanity" > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 64bdb8cd0606bbc4c1b11d69b2d0e7cd7b5dd78a > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Tue, 13 May 2025 11:39:41 UTC ## Summary by CodeRabbit - **New Features** - Introduced a new feature flag for AI agent instances, allowing for more granular control over AI agent-related functionality. - **Refactor** - Updated various components and selectors to use the new AI agent instance feature flag and related selectors, replacing previous flags and logic. - Separated agent and non-agent template handling for clearer template management. - Improved feature flag override capabilities, enabling dynamic overrides via external sources. - Added new selectors to better represent AI agent app and creation states. - Refined UI components and modals to reflect updated AI agent state flags. - Enhanced user authentication and signup flows with updated feature flag conditions. - **Bug Fixes** - Ensured consistent UI behavior and conditional rendering based on the updated feature flag logic. --- app/client/src/ce/entities/FeatureFlag.ts | 2 + .../pages/AdminSettings/config/auditlogs.ts | 6 +-- .../ce/pages/Applications/EmbedSnippetTab.tsx | 22 +++++------ .../src/ce/pages/Applications/index.tsx | 15 ++++---- .../Editor/gitSync/useReconnectModalData.ts | 12 +++--- .../ce/pages/Upgrade/AuditLogsUpgradePage.tsx | 8 ++-- app/client/src/ce/sagas/ApplicationSagas.tsx | 6 +-- .../src/ce/selectors/aiAgentSelectors.ts | 22 +++++++++-- app/client/src/ce/utils/signupHelpers.ts | 2 +- .../GlobalSearch/GlobalSearchHooks.tsx | 6 +-- app/client/src/ee/actions/aiAgentActions.ts | 9 +++++ .../src/pages/AdminSettings/Profile/index.tsx | 8 ++-- .../components/AppSettings/AppSettings.tsx | 6 +-- .../EmbedSnippet/PrivateEmbeddingContent.tsx | 10 ++--- .../pages/Editor/DataSourceEditor/index.tsx | 25 ++++++++---- .../EditorName/useNavigationMenuData.ts | 12 +++--- app/client/src/pages/Editor/HelpButton.tsx | 6 +-- .../Editor/SaaSEditor/DatasourceForm.tsx | 16 ++++---- .../Editor/gitSync/ImportSuccessModal.tsx | 6 +-- .../gitSync/ReconnectDatasourceModal.tsx | 38 +++++++++++-------- app/client/src/pages/UserAuth/Container.tsx | 18 ++++++--- .../src/pages/UserAuth/LeftSideContent.tsx | 8 ++-- app/client/src/pages/UserAuth/SignUp.tsx | 10 ++--- .../common/SearchBar/HomepageHeaderAction.tsx | 6 +-- .../src/pages/common/datasourceAuth/index.tsx | 6 +-- app/client/src/pages/setup/SignupSuccess.tsx | 8 ++-- app/client/src/sagas/TemplatesSagas.ts | 16 ++++---- .../src/selectors/templatesSelectors.tsx | 31 +++++---------- .../src/utils/hooks/useFeatureFlagOverride.ts | 15 ++++++++ 29 files changed, 202 insertions(+), 153 deletions(-) diff --git a/app/client/src/ce/entities/FeatureFlag.ts b/app/client/src/ce/entities/FeatureFlag.ts index afaa81c67f..952b8003f4 100644 --- a/app/client/src/ce/entities/FeatureFlag.ts +++ b/app/client/src/ce/entities/FeatureFlag.ts @@ -58,6 +58,7 @@ export const FEATURE_FLAG = { "license_external_saas_plugins_enabled", release_computation_cache_enabled: "release_computation_cache_enabled", release_ai_chat_integrations_enabled: "release_ai_chat_integrations_enabled", + license_ai_agent_instance_enabled: "license_ai_agent_instance_enabled", } as const; export type FeatureFlag = keyof typeof FEATURE_FLAG; @@ -106,6 +107,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = { license_external_saas_plugins_enabled: false, release_computation_cache_enabled: false, release_ai_chat_integrations_enabled: false, + license_ai_agent_instance_enabled: false, }; export const AB_TESTING_EVENT_KEYS = { diff --git a/app/client/src/ce/pages/AdminSettings/config/auditlogs.ts b/app/client/src/ce/pages/AdminSettings/config/auditlogs.ts index 275a76af40..20c37a75b9 100644 --- a/app/client/src/ce/pages/AdminSettings/config/auditlogs.ts +++ b/app/client/src/ce/pages/AdminSettings/config/auditlogs.ts @@ -6,9 +6,9 @@ import { } from "ee/pages/AdminSettings/config/types"; import { AuditLogsUpgradePage } from "../../Upgrade/AuditLogsUpgradePage"; import store from "store"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors"; -const isAIAgentFlowEnabled = getIsAiAgentFlowEnabled(store.getState()); +const isAIAgentInstanceEnabled = getIsAiAgentInstanceEnabled(store.getState()); export const config: AdminConfigType = { icon: "file-list-2-line", @@ -19,5 +19,5 @@ export const config: AdminConfigType = { title: "Audit logs", canSave: false, isFeatureEnabled: false, - isEnterprise: isAIAgentFlowEnabled ? true : false, + isEnterprise: isAIAgentInstanceEnabled ? true : false, } as AdminConfigType; diff --git a/app/client/src/ce/pages/Applications/EmbedSnippetTab.tsx b/app/client/src/ce/pages/Applications/EmbedSnippetTab.tsx index 37642b65f9..4f1056ffa7 100644 --- a/app/client/src/ce/pages/Applications/EmbedSnippetTab.tsx +++ b/app/client/src/ce/pages/Applications/EmbedSnippetTab.tsx @@ -16,7 +16,7 @@ import { PrivateEmbedSettings } from "ee/pages/Applications/PrivateEmbedSettings import { getCurrentApplication } from "ee/selectors/applicationSelectors"; import { useIsCloudBillingEnabled } from "hooks"; import { ChromeExtensionBanner } from "ee/pages/Applications/ChromeExtensionBanner"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors"; export const StyledPropertyHelpLabel = styled(PropertyHelpLabel)` .bp3-popover-content > div { @@ -53,10 +53,10 @@ export function ShareModal() { const currentApplicationDetails = useSelector(getCurrentApplication); const isPublicApp = currentApplicationDetails?.isPublic || false; const isCloudBillingEnabled = useIsCloudBillingEnabled(); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAgentApp = useSelector(getIsAiAgentApp); const snippetUrl = getSnippetUrl( embedSnippet.appViewEndPoint, - isPublicApp || isAiAgentFlowEnabled, + isPublicApp || isAgentApp, selectedMethod, ); @@ -92,7 +92,7 @@ export function ShareModal() { )} - {Boolean(isAiAgentFlowEnabled) === false && ( + {Boolean(isAgentApp) === false && ( )} - {!isPublicApp && !isAiAgentFlowEnabled && ( + {!isPublicApp && !isAgentApp && ( )} - {Boolean(isAiAgentFlowEnabled) === false && ( + {Boolean(isAgentApp) === false && ( )} - {!isPublicApp && !isAiAgentFlowEnabled && ( + {!isPublicApp && !isAgentApp && ( ) : ( <> - {!isAiAgentFlowEnabled && ( + {!isAiAgentInstanceEnabled && ( )} - {((isAnvilEnabled && anvilApplications.length > 0) || - isAiAgentFlowEnabled) && ( + {isAiAgentFlowEnabled && ( getApplicationByIdFromWorkspaces(state, appId ?? ""), ); @@ -31,18 +31,16 @@ function useReconnectModalData({ appId, pageId }: UseReconnectModalDataProps) { basePageId, branch, params: { - type: isAiAgentFlowEnabled ? "agent" : undefined, + type: isCreatingAgent ? "agent" : undefined, }, }); return { skipMessage: createMessage( - isAiAgentFlowEnabled - ? SKIP_TO_APPLICATION_FOR_AGENTS - : SKIP_TO_APPLICATION, + isCreatingAgent ? SKIP_TO_APPLICATION_FOR_AGENTS : SKIP_TO_APPLICATION, ), missingDsCredentialsDescription: createMessage( - isAiAgentFlowEnabled + isCreatingAgent ? RECONNECT_MISSING_DATASOURCE_CREDENTIALS_DESCRIPTION_FOR_AGENTS : RECONNECT_MISSING_DATASOURCE_CREDENTIALS_DESCRIPTION, ), diff --git a/app/client/src/ce/pages/Upgrade/AuditLogsUpgradePage.tsx b/app/client/src/ce/pages/Upgrade/AuditLogsUpgradePage.tsx index 717e5129a2..a342bd4e3b 100644 --- a/app/client/src/ce/pages/Upgrade/AuditLogsUpgradePage.tsx +++ b/app/client/src/ce/pages/Upgrade/AuditLogsUpgradePage.tsx @@ -20,7 +20,7 @@ import { import useOnUpgrade from "utils/hooks/useOnUpgrade"; import { RampFeature, RampSection } from "utils/ProductRamps/RampsControlList"; import { useSelector } from "react-redux"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors"; export function AuditLogsUpgradePage() { const { onUpgrade } = useOnUpgrade({ @@ -29,7 +29,7 @@ export function AuditLogsUpgradePage() { featureName: RampFeature.AuditLogs, sectionName: RampSection.AdminSettings, }); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAiAgentInstanceEnabled = useSelector(getIsAiAgentInstanceEnabled); const header: Header = { heading: createMessage(INTRODUCING, "audit logs"), @@ -83,9 +83,9 @@ export function AuditLogsUpgradePage() { message: createMessage( EXCLUSIVE_TO_BUSINESS, ["audit logs"], - isAiAgentFlowEnabled ? "enterprise" : "business", + isAiAgentInstanceEnabled ? "enterprise" : "business", ), - isEnterprise: isAiAgentFlowEnabled ? true : false, + isEnterprise: isAiAgentInstanceEnabled ? true : false, }; const props = { header, carousel, footer }; diff --git a/app/client/src/ce/sagas/ApplicationSagas.tsx b/app/client/src/ce/sagas/ApplicationSagas.tsx index c6cc2ec854..baf2e30f5a 100644 --- a/app/client/src/ce/sagas/ApplicationSagas.tsx +++ b/app/client/src/ce/sagas/ApplicationSagas.tsx @@ -121,7 +121,7 @@ import type { Page } from "entities/Page"; import type { ApplicationPayload } from "entities/Application"; import { objectKeys } from "@appsmith/utils"; import { findDefaultPage } from "pages/utils"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors"; export let windowReference: Window | null = null; @@ -802,6 +802,7 @@ export function* showReconnectDatasourcesModalSaga( yield put(setWorkspaceIdForImport({ editorId: application.id, workspaceId })); yield put(setPageIdForImport(pageId)); + yield put(setIsReconnectingDatasourcesModalOpen({ isOpen: true })); } @@ -1005,8 +1006,7 @@ export function* initDatasourceConnectionDuringImport( }>, ) { const workspaceId = action.payload.workspaceId; - const isAgentFlowEnabled: boolean = yield select(getIsAiAgentFlowEnabled); - + const isAgentFlowEnabled: boolean = yield select(getIsAiAgentInstanceEnabled); const pluginsAndDatasourcesCalls: boolean = yield failFastApiCalls( [fetchPlugins({ workspaceId }), fetchDatasources({ workspaceId })], [ diff --git a/app/client/src/ce/selectors/aiAgentSelectors.ts b/app/client/src/ce/selectors/aiAgentSelectors.ts index da6c555174..073d75bead 100644 --- a/app/client/src/ce/selectors/aiAgentSelectors.ts +++ b/app/client/src/ce/selectors/aiAgentSelectors.ts @@ -1,11 +1,25 @@ -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import type { DefaultRootState } from "react-redux"; -import { selectFeatureFlagCheck } from "ee/selectors/featureFlagsSelectors"; export const getAgentChatQuery = () => { return undefined; }; -export const getIsAiAgentFlowEnabled = (state: DefaultRootState) => { - return selectFeatureFlagCheck(state, FEATURE_FLAG.license_ai_agent_enabled); +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const getIsAiAgentInstanceEnabled = (state: DefaultRootState) => { + return false; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const getIsAiAgentFlowEnabled = (state: DefaultRootState) => { + return false; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const getIsAiAgentApp = (state: DefaultRootState) => { + return false; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const getIsCreatingAgent = (state: DefaultRootState) => { + return false; }; diff --git a/app/client/src/ce/utils/signupHelpers.ts b/app/client/src/ce/utils/signupHelpers.ts index 6c8a82ab4c..cf6eae31cb 100644 --- a/app/client/src/ce/utils/signupHelpers.ts +++ b/app/client/src/ce/utils/signupHelpers.ts @@ -23,7 +23,7 @@ export interface RedirectUserAfterSignupProps { shouldEnableFirstTimeUserOnboarding: string | null; validLicense?: boolean; dispatch: Dispatch; - isAiAgentFlowEnabled: boolean; + isAiAgentInstanceEnabled: boolean; isOnLoginPage: boolean; } diff --git a/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx b/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx index 4f4928bf6c..f141e2cf9a 100644 --- a/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx +++ b/app/client/src/components/editorComponents/GlobalSearch/GlobalSearchHooks.tsx @@ -47,7 +47,7 @@ import { checkIfJSObjectCreationAllowed, useWorkflowOptions, } from "ee/utils/workflowHelpers"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors"; export interface FilterFileOperationsProps { canCreateActions: boolean; @@ -84,7 +84,7 @@ export const useFilteredFileOperations = ({ ); const isGACEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAgentApp = useSelector(getIsAiAgentApp); const AiPlugin = useSelector((state: DefaultRootState) => getPluginByPackageName(state, PluginPackageName.APPSMITH_AI), ); @@ -106,7 +106,7 @@ export const useFilteredFileOperations = ({ .filter((ds) => { // We don't want to show the AI datasource in the // lists if the AI agent flow is enabled - if (isAiAgentFlowEnabled && AiPlugin) { + if (isAgentApp && AiPlugin) { return AiPlugin.id !== ds.pluginId; } diff --git a/app/client/src/ee/actions/aiAgentActions.ts b/app/client/src/ee/actions/aiAgentActions.ts index b76089bef2..4733938a03 100644 --- a/app/client/src/ee/actions/aiAgentActions.ts +++ b/app/client/src/ee/actions/aiAgentActions.ts @@ -21,3 +21,12 @@ export const toggleFCIntegrations = ({ type: "", payload: { isEnabled }, }); + +export const setIsCreatingAgent = ({ + isCreatingAgent, +}: { + isCreatingAgent: boolean; +}) => ({ + type: "", + payload: { isCreatingAgent }, +}); diff --git a/app/client/src/pages/AdminSettings/Profile/index.tsx b/app/client/src/pages/AdminSettings/Profile/index.tsx index 741badcd83..1ea6bc68ca 100644 --- a/app/client/src/pages/AdminSettings/Profile/index.tsx +++ b/app/client/src/pages/AdminSettings/Profile/index.tsx @@ -50,7 +50,7 @@ import { import { Classes } from "@blueprintjs/core"; import { useGitModEnabled } from "pages/Editor/gitSync/hooks/modHooks"; import useGlobalProfile from "git/hooks/useGlobalProfile"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors"; const nameValidator = ( value: string, @@ -95,7 +95,7 @@ export const Profile = () => { ); const [authorName, setAuthorNameInState] = useState(gitConfig?.authorName); const [authorEmail, setAuthorEmailInState] = useState(gitConfig?.authorEmail); - const isAIAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAiAgentInstanceEnabled = useSelector(getIsAiAgentInstanceEnabled); useEffect(() => { setIsSaving(false); @@ -277,12 +277,12 @@ export const Profile = () => { - {!isAIAgentFlowEnabled && ( + {!isAiAgentInstanceEnabled && ( Git author )} - {!isAIAgentFlowEnabled && ( + {!isAiAgentInstanceEnabled && ( {isFetching && } diff --git a/app/client/src/pages/AppIDE/components/AppSettings/AppSettings.tsx b/app/client/src/pages/AppIDE/components/AppSettings/AppSettings.tsx index ee2cea1922..87444f799a 100644 --- a/app/client/src/pages/AppIDE/components/AppSettings/AppSettings.tsx +++ b/app/client/src/pages/AppIDE/components/AppSettings/AppSettings.tsx @@ -34,7 +34,7 @@ import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import { Divider } from "@appsmith/ads"; import { ImportAppSettings } from "./components/ImportAppSettings"; import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors"; export enum AppSettingsTabs { General, @@ -194,9 +194,9 @@ function AppSettings() { }, ]; - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAgentApp = useSelector(getIsAiAgentApp); - if (isAiAgentFlowEnabled) { + if (isAgentApp) { SectionHeadersConfig = SectionHeadersConfig.filter( (config) => config.id !== "t--navigation-settings-header", ); diff --git a/app/client/src/pages/Applications/EmbedSnippet/PrivateEmbeddingContent.tsx b/app/client/src/pages/Applications/EmbedSnippet/PrivateEmbeddingContent.tsx index 14e9ea5b25..8bafaba18f 100644 --- a/app/client/src/pages/Applications/EmbedSnippet/PrivateEmbeddingContent.tsx +++ b/app/client/src/pages/Applications/EmbedSnippet/PrivateEmbeddingContent.tsx @@ -12,7 +12,7 @@ import { getRampLink, showProductRamps } from "ee/selectors/rampSelectors"; import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import EnterpriseTag from "components/EnterpriseTag"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors"; function PrivateEmbeddingContent(props: { // TODO: Fix this the next time the file is edited @@ -56,10 +56,10 @@ export function PrivateEmbedRampModal() { false, isPrivateEmbedEnabled, ); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAgentApp = useSelector(getIsAiAgentApp); const canShowRamp = useSelector(showRampSelector); - if (canShowRamp && !isAiAgentFlowEnabled) { + if (canShowRamp && !isAgentApp) { return (
@@ -108,10 +108,10 @@ export function PrivateEmbedRampSidebar() { false, isPrivateEmbedEnabled, ); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAgentApp = useSelector(getIsAiAgentApp); const canShowRamp = useSelector(showRampSelector); - if (canShowRamp && !isAiAgentFlowEnabled) { + if (canShowRamp && !isAgentApp) { return (
diff --git a/app/client/src/pages/Editor/DataSourceEditor/index.tsx b/app/client/src/pages/Editor/DataSourceEditor/index.tsx index a7b3ed0571..6900870ef2 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/index.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/index.tsx @@ -103,7 +103,10 @@ import DatasourceTabs from "../DatasourceInfo/DatasorceTabs"; import DatasourceInformation, { ViewModeWrapper } from "./DatasourceSection"; import { convertToPageIdSelector } from "selectors/pageListSelectors"; import { getApplicationByIdFromWorkspaces } from "ee/selectors/applicationSelectors"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { + getIsAiAgentApp, + getIsCreatingAgent, +} from "ee/selectors/aiAgentSelectors"; interface ReduxStateProps { canDeleteDatasource: boolean; @@ -144,7 +147,8 @@ interface ReduxStateProps { featureFlags?: FeatureFlags; isPluginAllowedToPreviewData: boolean; isOnboardingFlow?: boolean; - isAiAgentFlowEnabled?: boolean; + isCreatingAgent?: boolean; + isAgentApp?: boolean; } const Form = styled.div` @@ -162,9 +166,11 @@ type Props = ReduxStateProps & basePageId: string; }>; -export const DSEditorWrapper = styled.div<{ isAiAgentFlowEnabled?: boolean }>` +export const DSEditorWrapper = styled.div<{ + isCreatingAiAgent?: boolean; +}>` height: ${(props) => - props.isAiAgentFlowEnabled + props.isCreatingAiAgent ? `auto` : `calc(100vh - ${props.theme.headerHeight})`}; overflow: hidden; @@ -1027,7 +1033,9 @@ class DatasourceEditorRouter extends React.Component { > {viewMode && !isInsideReconnectModal ? ( this.renderTabsForViewMode() @@ -1164,8 +1172,8 @@ const mapStateToProps = ( const featureFlags = selectFeatureFlags(state); const isFeatureEnabled = isGACEnabled(featureFlags); - const isAiAgentFlowEnabled = getIsAiAgentFlowEnabled(state); - + const isAgentApp = getIsAiAgentApp(state); + const isCreatingAgent = getIsCreatingAgent(state); const canManageDatasource = getHasManageDatasourcePermission( isFeatureEnabled, datasourcePermissions, @@ -1233,7 +1241,8 @@ const mapStateToProps = ( defaultKeyValueArrayConfig, initialValue, showDebugger, - isAiAgentFlowEnabled, + isAgentApp, + isCreatingAgent, }; }; diff --git a/app/client/src/pages/Editor/EditorName/useNavigationMenuData.ts b/app/client/src/pages/Editor/EditorName/useNavigationMenuData.ts index 28b48702ea..5762e06da4 100644 --- a/app/client/src/pages/Editor/EditorName/useNavigationMenuData.ts +++ b/app/client/src/pages/Editor/EditorName/useNavigationMenuData.ts @@ -24,7 +24,7 @@ import { toast } from "@appsmith/ads"; import { DOCS_AI_BASE_URL, DOCS_BASE_URL } from "constants/ThirdPartyConstants"; import { getAppsmithConfigs } from "ee/configs"; import { getCurrentUser } from "selectors/usersSelectors"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors"; const { cloudHosting, intercomAppID } = getAppsmithConfigs(); @@ -108,7 +108,7 @@ export const useNavigationMenuData = ({ } }, [applicationId, dispatch, history]); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAgentApp = useSelector(getIsAiAgentApp); return useMemo( () => @@ -152,9 +152,7 @@ export const useNavigationMenuData = ({ { text: "Documentation", onClick: () => - openExternalLink( - isAiAgentFlowEnabled ? DOCS_AI_BASE_URL : DOCS_BASE_URL, - ), + openExternalLink(isAgentApp ? DOCS_AI_BASE_URL : DOCS_BASE_URL), type: MenuTypes.MENU, isVisible: true, startIcon: "book-line", @@ -166,7 +164,7 @@ export const useNavigationMenuData = ({ "https://github.com/appsmithorg/appsmith/issues/new/choose", ), type: MenuTypes.MENU, - isVisible: !isAiAgentFlowEnabled, + isVisible: !isAgentApp, startIcon: "bug-line", }, { @@ -191,7 +189,7 @@ export const useNavigationMenuData = ({ hasExportPermission, hasDeletePermission, deleteApplication, - isAiAgentFlowEnabled, + isAgentApp, setForkApplicationModalOpen, isIntercomConsentGiven, dispatch, diff --git a/app/client/src/pages/Editor/HelpButton.tsx b/app/client/src/pages/Editor/HelpButton.tsx index c5b2e5c518..f99b43def3 100644 --- a/app/client/src/pages/Editor/HelpButton.tsx +++ b/app/client/src/pages/Editor/HelpButton.tsx @@ -37,7 +37,7 @@ import { showSignpostingModal } from "actions/onboardingActions"; import TooltipContent from "./FirstTimeUserOnboarding/TooltipContent"; import { getInstanceId } from "ee/selectors/organizationSelectors"; import { updateIntercomConsent, updateUserDetails } from "actions/userActions"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors"; import { DOCS_AI_BASE_URL } from "constants/ThirdPartyConstants"; const { appVersion, cloudHosting, intercomAppID } = getAppsmithConfigs(); @@ -190,9 +190,9 @@ function HelpButton() { } : {}; - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAgentApp = useSelector(getIsAiAgentApp); - if (isAiAgentFlowEnabled) { + if (isAgentApp) { const docItem = HELP_MENU_ITEMS.find( (item) => item.label === "Documentation", ); diff --git a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx index 1844374056..a5646e0226 100644 --- a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx +++ b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @@ -94,7 +94,10 @@ import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import DatasourceTabs from "../DatasourceInfo/DatasorceTabs"; import { getCurrentApplicationIdForCreateNewApp } from "ee/selectors/applicationSelectors"; import { convertToPageIdSelector } from "selectors/pageListSelectors"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { + getIsAiAgentApp, + getIsCreatingAgent, +} from "ee/selectors/aiAgentSelectors"; const ViewModeContainer = styled.div` display: flex; @@ -189,7 +192,7 @@ interface SaasEditorWrappperProps { datasourceId: string; pageId: string; pluginPackageName: string; - isAiAgentFlowEnabled?: boolean; + isCreatingAiAgent?: boolean; } interface RouteProps { datasourceId: string; @@ -645,9 +648,7 @@ class DatasourceSaaSEditor extends JSONtoForm { showingTabsOnViewMode && "saas-form-resizer-content-show-tabs" }`} > - + { // should plugin be able to preview data const isPluginAllowedToPreviewData = !!plugin && isEnabledForPreviewData(datasource as Datasource, plugin); - const isAiAgentFlowEnabled = getIsAiAgentFlowEnabled(state); + const isCreatingAgent = getIsCreatingAgent(state); + const isAgentApp = getIsAiAgentApp(state); return { datasource, @@ -895,7 +897,7 @@ const mapStateToProps = (state: DefaultRootState, props: any) => { isPluginAuthFailed, featureFlags: selectFeatureFlags(state), isPluginAllowedToPreviewData, - isAiAgentFlowEnabled, + isCreatingAiAgent: isCreatingAgent || isAgentApp, }; }; diff --git a/app/client/src/pages/Editor/gitSync/ImportSuccessModal.tsx b/app/client/src/pages/Editor/gitSync/ImportSuccessModal.tsx index 9a535f3952..e154e7a9aa 100644 --- a/app/client/src/pages/Editor/gitSync/ImportSuccessModal.tsx +++ b/app/client/src/pages/Editor/gitSync/ImportSuccessModal.tsx @@ -16,7 +16,7 @@ import { Text, } from "@appsmith/ads"; import { useSelector } from "react-redux"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors"; const BodyContainer = styled.div` display: flex; @@ -42,7 +42,7 @@ function ImportSuccessModal(props: ImportSuccessModalProps) { const importedAppSuccess = localStorage.getItem("importSuccess"); // const isOpen = importedAppSuccess === "true"; const [isOpen, setIsOpen] = useState(importedAppSuccess === "true"); - const isAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAiAgentApp = useSelector(getIsAiAgentApp); const onClose = (open: boolean) => { if (!open) { @@ -56,7 +56,7 @@ function ImportSuccessModal(props: ImportSuccessModalProps) { }; return ( - + Datasource configured diff --git a/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx b/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx index 8e7dc01521..6289759b57 100644 --- a/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx +++ b/app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx @@ -76,7 +76,8 @@ import useReconnectModalData from "ee/pages/Editor/gitSync/useReconnectModalData import { resetImportData } from "ee/actions/workspaceActions"; import { getLoadingTokenForDatasourceId } from "selectors/datasourceSelectors"; import ReconnectDatasourceForm from "Datasource/components/ReconnectDatasourceForm"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsCreatingAgent } from "ee/selectors/aiAgentSelectors"; +import { setIsCreatingAgent } from "ee/actions/aiAgentActions"; const Section = styled.div` display: flex; @@ -87,10 +88,10 @@ const Section = styled.div` width: calc(100% - 206px); `; -const BodyContainer = styled.div<{ isAiAgentFlowEnabled?: boolean }>` +const BodyContainer = styled.div<{ isCreatingAiAgent?: boolean }>` flex: 3; - height: ${(props) => (props.isAiAgentFlowEnabled ? "auto" : "640px")}; - max-height: ${(props) => (props.isAiAgentFlowEnabled ? "auto" : "82vh")}; + height: ${(props) => (props.isCreatingAiAgent ? "auto" : "640px")}; + max-height: ${(props) => (props.isCreatingAiAgent ? "auto" : "82vh")}; `; // TODO: Removed usage of "t--" classes since they clash with the test classes. @@ -226,9 +227,9 @@ const ModalHeaderWrapper = styled.div<{ isAgentFlowEnabled: boolean }>` `; const ModalContentWrapper = styled(ModalContent)<{ - isAiAgentFlowEnabled?: boolean; + isCreatingAiAgent?: boolean; }>` - width: ${(props) => (props.isAiAgentFlowEnabled ? "auto" : "100%")}; + width: ${(props) => (props.isCreatingAiAgent ? "auto" : "100%")}; `; const ModalBodyWrapper = styled(ModalBody)` overflow-y: hidden; @@ -342,7 +343,7 @@ function ReconnectDatasourceModal() { parentEntityId, // appId or packageId from query params skipMessage, } = useReconnectModalData({ pageId, appId }); - const isAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isCreatingAgent = useSelector(getIsCreatingAgent); // when redirecting from oauth, processing the status if (isImport) { @@ -624,27 +625,32 @@ function ReconnectDatasourceModal() { }; return ( - + { + if (!isOpen) { + dispatch(setIsCreatingAgent({ isCreatingAgent: false })); + } + }} + open={isModalOpen} + > - + - {isAgentFlowEnabled - ? "Connect Datasources" - : "Reconnect datasources"} + {isCreatingAgent ? "Connect Datasources" : "Reconnect datasources"} - - {!isAgentFlowEnabled && ( + + {!isCreatingAgent && ( {createMessage(RECONNECT_MISSING_DATASOURCE_CREDENTIALS)} diff --git a/app/client/src/pages/UserAuth/Container.tsx b/app/client/src/pages/UserAuth/Container.tsx index ab3ffc43ab..911f209760 100644 --- a/app/client/src/pages/UserAuth/Container.tsx +++ b/app/client/src/pages/UserAuth/Container.tsx @@ -7,8 +7,10 @@ import LeftSideContent from "./LeftSideContent"; import { getAppsmithConfigs } from "ee/configs"; import { useIsMobileDevice } from "utils/hooks/useDeviceDetect"; import styled from "styled-components"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors"; import clsx from "clsx"; +import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors"; +import { isBrandingEnabled, isMultiOrgFFEnabled } from "ee/utils/planHelpers"; interface ContainerProps { title: string; @@ -45,18 +47,24 @@ function Container(props: ContainerProps) { const organizationConfig = useSelector(getOrganizationConfig); const { cloudHosting } = getAppsmithConfigs(); const isMobileDevice = useIsMobileDevice(); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const featureFlags = useSelector(selectFeatureFlags); + const multiOrgEnabled = isMultiOrgFFEnabled(featureFlags); + const brandingEnabled = isBrandingEnabled(featureFlags); + + const shouldShowLeftSideContent = + cloudHosting && !isMobileDevice && !multiOrgEnabled && brandingEnabled; + const isAiAgentInstanceEnabled = useSelector(getIsAiAgentInstanceEnabled); return ( - {cloudHosting && !isMobileDevice && } + {shouldShowLeftSideContent && } - {!isAiAgentFlowEnabled && ( + {!isAiAgentInstanceEnabled && (
"{QUOTE.quote}" @@ -102,7 +102,7 @@ function LeftSideContent() {
GSK logo { - if (!isFormLoginEnabled && !isAiAgentFlowEnabled) { + if (!isFormLoginEnabled && !isAiAgentInstanceEnabled) { const search = new URL(window.location.href)?.searchParams?.toString(); history.replace({ @@ -227,7 +227,7 @@ export function SignUp(props: SignUpFormProps) {
)} - {cloudHosting && !isAiAgentFlowEnabled && ( + {cloudHosting && !isAiAgentInstanceEnabled && ( <> or
@@ -251,7 +251,7 @@ export function SignUp(props: SignUpFormProps) { diff --git a/app/client/src/pages/common/SearchBar/HomepageHeaderAction.tsx b/app/client/src/pages/common/SearchBar/HomepageHeaderAction.tsx index 4c549807bf..b045472b46 100644 --- a/app/client/src/pages/common/SearchBar/HomepageHeaderAction.tsx +++ b/app/client/src/pages/common/SearchBar/HomepageHeaderAction.tsx @@ -40,7 +40,7 @@ import { IntercomConsent } from "pages/Editor/HelpButton"; import { DOCS_AI_BASE_URL, DOCS_BASE_URL } from "constants/ThirdPartyConstants"; import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; import styled from "styled-components"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors"; const { cloudHosting, intercomAppID } = getAppsmithConfigs(); export const VersionData = styled.div` @@ -71,7 +71,7 @@ const HomepageHeaderAction = ({ const { appVersion } = getAppsmithConfigs(); const howMuchTimeBefore = howMuchTimeBeforeText(appVersion.releaseDate); const [showIntercomConsent, setShowIntercomConsent] = useState(false); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAiAgentInstanceEnabled = useSelector(getIsAiAgentInstanceEnabled); if (!isHomePage || !!isCreateNewAppFlow) return null; @@ -129,7 +129,7 @@ const HomepageHeaderAction = ({ { - if (isAiAgentFlowEnabled) { + if (isAiAgentInstanceEnabled) { window.open(DOCS_AI_BASE_URL, "_blank"); return; diff --git a/app/client/src/pages/common/datasourceAuth/index.tsx b/app/client/src/pages/common/datasourceAuth/index.tsx index 1f26944308..51999ecf1e 100644 --- a/app/client/src/pages/common/datasourceAuth/index.tsx +++ b/app/client/src/pages/common/datasourceAuth/index.tsx @@ -45,7 +45,7 @@ import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { getHasManageDatasourcePermission } from "ee/utils/BusinessFeatures/permissionPageHelpers"; import { resetCurrentPluginIdForCreateNewApp } from "actions/onboardingActions"; import { useParentEntityDetailsFromParams } from "ee/entities/Engine/actionHelpers"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsCreatingAgent } from "ee/selectors/aiAgentSelectors"; interface Props { datasource: Datasource; @@ -200,7 +200,7 @@ function DatasourceAuth({ isInsideReconnectModal, ); - const isAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isCreatingAgent = useSelector(getIsCreatingAgent); useEffect(() => { if ( @@ -455,7 +455,7 @@ function DatasourceAuth({ size="md" > {createMessage( - isAgentFlowEnabled + isCreatingAgent ? CONNECT_DATASOURCE_BUTTON_TEXT_FOR_AGENTS : CONNECT_DATASOURCE_BUTTON_TEXT, )} diff --git a/app/client/src/pages/setup/SignupSuccess.tsx b/app/client/src/pages/setup/SignupSuccess.tsx index d0540ead82..af8ee38754 100644 --- a/app/client/src/pages/setup/SignupSuccess.tsx +++ b/app/client/src/pages/setup/SignupSuccess.tsx @@ -15,7 +15,7 @@ import { import { redirectUserAfterSignup } from "ee/utils/signupHelpers"; import { setUserSignedUpFlag } from "utils/storage"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; +import { getIsAiAgentInstanceEnabled } from "ee/selectors/aiAgentSelectors"; export function SignupSuccess() { const dispatch = useDispatch(); @@ -24,7 +24,7 @@ export function SignupSuccess() { const shouldEnableFirstTimeUserOnboarding = urlObject?.searchParams.get( "enableFirstTimeUserExperience", ); - const isAiAgentFlowEnabled = useSelector(getIsAiAgentFlowEnabled); + const isAiAgentInstanceEnabled = useSelector(getIsAiAgentInstanceEnabled); const validLicense = useSelector(isValidLicense); const user = useSelector(getCurrentUser); const isOnLoginPage = !useSelector(isWithinAnOrganization); @@ -42,7 +42,7 @@ export function SignupSuccess() { shouldEnableFirstTimeUserOnboarding, validLicense, dispatch, - isAiAgentFlowEnabled, + isAiAgentInstanceEnabled, isOnLoginPage, }), [ @@ -82,7 +82,7 @@ export function SignupSuccess() { user?.isSuperUser || ((user?.role || user?.proficiency) && user?.useCase) || shouldEnableFirstTimeUserOnboarding !== "true" || - isAiAgentFlowEnabled + isAiAgentInstanceEnabled ) { redirectUsingQueryParam(); diff --git a/app/client/src/sagas/TemplatesSagas.ts b/app/client/src/sagas/TemplatesSagas.ts index b63a466a39..7652921c4b 100644 --- a/app/client/src/sagas/TemplatesSagas.ts +++ b/app/client/src/sagas/TemplatesSagas.ts @@ -50,8 +50,7 @@ import { openCarbonModal, setCreateAgentModalOpen, } from "ee/actions/aiAgentActions"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; -import { getTemplatesByFlagSelector } from "selectors/templatesSelectors"; +import { getAgentTemplatesSelector } from "selectors/templatesSelectors"; const isAirgappedInstance = isAirgapped(); const AI_DATASOURCE_NAME = "AI Datasource"; @@ -82,9 +81,10 @@ function* getAllTemplatesSaga() { function* importTemplateToWorkspaceSaga( action: ReduxAction<{ templateId: string; workspaceId: string }>, ) { - const isAiAgentFlowEnabled: boolean = yield select(getIsAiAgentFlowEnabled); - const templates: ReturnType = yield select( - getTemplatesByFlagSelector, + const agentTemplates: ReturnType = + yield select(getAgentTemplatesSelector); + const isAgentTemplate: boolean = agentTemplates.some( + (template) => template.id === action.payload.templateId, ); try { @@ -108,8 +108,8 @@ function* importTemplateToWorkspaceSaga( payload: response.data.application, }); - if (isAiAgentFlowEnabled) { - const isScratchTemplate = templates.find( + if (isAgentTemplate) { + const isScratchTemplate = agentTemplates.find( (template) => template.title === "AI Agent", ); @@ -141,7 +141,7 @@ function* importTemplateToWorkspaceSaga( const pageURL = builderURL({ basePageId: application.defaultBasePageId, params: { - type: isAiAgentFlowEnabled ? "agent" : undefined, + type: isAgentTemplate ? "agent" : undefined, }, }); diff --git a/app/client/src/selectors/templatesSelectors.tsx b/app/client/src/selectors/templatesSelectors.tsx index 626424e617..8ea8199cfc 100644 --- a/app/client/src/selectors/templatesSelectors.tsx +++ b/app/client/src/selectors/templatesSelectors.tsx @@ -13,7 +13,6 @@ import Fuse from "fuse.js"; import type { Filter } from "pages/Templates/TemplateFilters"; import { TEMPLATE_BUILDING_BLOCKS_FILTER_FUNCTION_VALUE } from "pages/Templates/constants"; import { createSelector } from "reselect"; -import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors"; import type { DefaultRootState } from "react-redux"; const fuzzySearchOptions = { @@ -27,24 +26,14 @@ const fuzzySearchOptions = { const AGENT_TEMPLATES_USE_CASE = "Agent"; export const getTemplatesSelector = (state: DefaultRootState) => - state.ui.templates.templates; + state.ui.templates.templates.filter( + (template) => !template.useCases.includes(AGENT_TEMPLATES_USE_CASE), + ); -export const getTemplatesByFlagSelector = createSelector( - (state: DefaultRootState) => state.ui.templates.templates, - getIsAiAgentFlowEnabled, - (templates, isAiAgentFlowEnabled) => { - // For agents, we only show the templates that have the use case "Agent". - // The "Agent" use case acts as a filter for us to just show the templates - // that are relevant to agents. - return templates.filter((template) => { - if (isAiAgentFlowEnabled) { - return template.useCases.includes(AGENT_TEMPLATES_USE_CASE); - } - - return template.useCases.includes(AGENT_TEMPLATES_USE_CASE) === false; - }); - }, -); +export const getAgentTemplatesSelector = (state: DefaultRootState) => + state.ui.templates.templates.filter((template) => + template.useCases.includes(AGENT_TEMPLATES_USE_CASE), + ); export const isImportingTemplateSelector = (state: DefaultRootState) => state.ui.templates.isImportingTemplate; @@ -116,7 +105,7 @@ export const getBuildingBlockExplorerCards = createSelector( ); export const getFilteredTemplateList = createSelector( - getTemplatesByFlagSelector, + getTemplatesSelector, getTemplateFilterSelector, getTemplateFiltersLength, (templates, templatesFilters, numberOfFiltersApplied) => { @@ -180,7 +169,7 @@ export const getSearchedTemplateList = createSelector( // Get the list of datasources which are used by templates export const templatesDatasourceFiltersSelector = createSelector( - getTemplatesByFlagSelector, + getTemplatesSelector, getDefaultPlugins, (templates, plugins) => { const datasourceFilters: { label: string; value: string }[] = []; @@ -216,7 +205,7 @@ export const allTemplatesFiltersSelector = (state: DefaultRootState) => // Get all filters which is associated with atleast one template // If no template is associated with a filter, then the filter shouldn't be in the filter list export const getFilterListSelector = createSelector( - getTemplatesByFlagSelector, + getTemplatesSelector, allTemplatesFiltersSelector, (templates, allTemplateFilters) => { const FUNCTIONS_FILTER = "functions"; diff --git a/app/client/src/utils/hooks/useFeatureFlagOverride.ts b/app/client/src/utils/hooks/useFeatureFlagOverride.ts index 03dbe071a0..f1cef305db 100644 --- a/app/client/src/utils/hooks/useFeatureFlagOverride.ts +++ b/app/client/src/utils/hooks/useFeatureFlagOverride.ts @@ -17,6 +17,7 @@ export const AvailableFeaturesToOverride: FeatureFlag[] = [ "release_layout_conversion_enabled", "license_ai_agent_enabled", "release_ai_chat_integrations_enabled", + "license_ai_agent_instance_enabled", ]; export type OverriddenFeatureFlags = Partial>; @@ -24,6 +25,20 @@ export const useFeatureFlagOverride = () => { const dispatch = useDispatch(); const areFeatureFlagsFetched = useSelector(getFeatureFlagsFetched); + /** + * This is for listeninging the message from the feature flag overrrider chrome extension + */ + useEffect(() => { + window.addEventListener("message", (event) => { + if (event.data.action === "featureFlagOverrideValuesSet") { + const featureFlagValues = event.data.values; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (window as any).overrideFeatureFlag(featureFlagValues); + } + }); + }, []); + /** * Fetches the feature flag override values and updates the state. */