chore: Add separate flow for Anvil app publish (#39891)
## Description Anvil apps can have additional tasks before publishing so separate it out Fixes https://www.notion.so/appsmith/Prompt-users-to-save-tools-on-deploy-1bcfe271b0e2804abe30fe462061f454?pvs=4 ## Automation /ok-to-test tags="@tag.Sanity" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/14052281640> > Commit: df611bee4f3c54107f2478f97b9263491b2b2e2e > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14052281640&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Sanity` > Spec: > <hr>Tue, 25 Mar 2025 06:04:32 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced an enhanced publishing flow for Anvil applications with dedicated actions for initiation, success, and error scenarios. - Updated the deployment behavior to automatically use the Anvil publishing process when enabled. - **Refactor** - Streamlined the code by removing legacy functionality related to schema generation. - Consolidated utility methods for determining default pages for improved consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
b61b12ec00
commit
3d1192aba1
|
|
@ -20,16 +20,6 @@ export const isActionDirty = (id: string) =>
|
||||||
const getActionRunningState = (state: AppState) =>
|
const getActionRunningState = (state: AppState) =>
|
||||||
state.ui.pluginActionEditor.isRunning;
|
state.ui.pluginActionEditor.isRunning;
|
||||||
|
|
||||||
const getActionSchemaGeneratingState = (state: AppState) =>
|
|
||||||
state.ui.pluginActionEditor.isSchemaGenerating;
|
|
||||||
|
|
||||||
export const isActionSchemaGenerating = (id: string) =>
|
|
||||||
createSelector(
|
|
||||||
[getActionSchemaGeneratingState],
|
|
||||||
(isSchemaGeneratingMap) =>
|
|
||||||
id in isSchemaGeneratingMap && isSchemaGeneratingMap[id],
|
|
||||||
);
|
|
||||||
|
|
||||||
export const isActionRunning = (id: string) =>
|
export const isActionRunning = (id: string) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
[getActionRunningState],
|
[getActionRunningState],
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ import type {
|
||||||
ImportApplicationRequest,
|
ImportApplicationRequest,
|
||||||
UpdateApplicationPayload,
|
UpdateApplicationPayload,
|
||||||
} from "ee/api/ApplicationApi";
|
} from "ee/api/ApplicationApi";
|
||||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
import {
|
||||||
|
ReduxActionErrorTypes,
|
||||||
|
ReduxActionTypes,
|
||||||
|
} from "ee/constants/ReduxActionConstants";
|
||||||
import type { NavigationSetting, ThemeSetting } from "constants/AppConstants";
|
import type { NavigationSetting, ThemeSetting } from "constants/AppConstants";
|
||||||
import type { IconNames } from "@appsmith/ads";
|
import type { IconNames } from "@appsmith/ads";
|
||||||
import type { Datasource } from "entities/Datasource";
|
import type { Datasource } from "entities/Datasource";
|
||||||
|
|
@ -154,6 +157,27 @@ export const publishApplication = (applicationId: string) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const publishAnvilApplication = (applicationId: string) => {
|
||||||
|
return {
|
||||||
|
type: ReduxActionTypes.PUBLISH_ANVIL_APPLICATION_INIT,
|
||||||
|
payload: {
|
||||||
|
applicationId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const publishAnvilApplicationSuccess = () => {
|
||||||
|
return {
|
||||||
|
type: ReduxActionTypes.PUBLISH_ANVIL_APPLICATION_SUCCESS,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const publishAnvilApplicationError = () => {
|
||||||
|
return {
|
||||||
|
type: ReduxActionErrorTypes.PUBLISH_ANVIL_APPLICATION_ERROR,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const importApplication = (appDetails: ImportApplicationRequest) => {
|
export const importApplication = (appDetails: ImportApplicationRequest) => {
|
||||||
return {
|
return {
|
||||||
type: ReduxActionTypes.IMPORT_APPLICATION_INIT,
|
type: ReduxActionTypes.IMPORT_APPLICATION_INIT,
|
||||||
|
|
|
||||||
|
|
@ -984,6 +984,8 @@ const AppViewActionTypes = {
|
||||||
FETCH_PUBLISHED_PAGE_RESOURCES_INIT: "FETCH_PUBLISHED_PAGE_RESOURCES_INIT",
|
FETCH_PUBLISHED_PAGE_RESOURCES_INIT: "FETCH_PUBLISHED_PAGE_RESOURCES_INIT",
|
||||||
FETCH_PUBLISHED_PAGE_RESOURCES_SUCCESS:
|
FETCH_PUBLISHED_PAGE_RESOURCES_SUCCESS:
|
||||||
"FETCH_PUBLISHED_PAGE_RESOURCES_SUCCESS",
|
"FETCH_PUBLISHED_PAGE_RESOURCES_SUCCESS",
|
||||||
|
PUBLISH_ANVIL_APPLICATION_INIT: "PUBLISH_ANVIL_APPLICATION_INIT",
|
||||||
|
PUBLISH_ANVIL_APPLICATION_SUCCESS: "PUBLISH_ANVIL_APPLICATION_SUCCESS",
|
||||||
};
|
};
|
||||||
|
|
||||||
const AppViewActionErrorTypes = {
|
const AppViewActionErrorTypes = {
|
||||||
|
|
@ -993,6 +995,7 @@ const AppViewActionErrorTypes = {
|
||||||
FETCH_ACTIONS_VIEW_MODE_ERROR: "FETCH_ACTION_VIEW_MODE_ERROR",
|
FETCH_ACTIONS_VIEW_MODE_ERROR: "FETCH_ACTION_VIEW_MODE_ERROR",
|
||||||
FETCH_JS_ACTIONS_VIEW_MODE_ERROR: "FETCH_JS_ACTIONS_VIEW_MODE_ERROR",
|
FETCH_JS_ACTIONS_VIEW_MODE_ERROR: "FETCH_JS_ACTIONS_VIEW_MODE_ERROR",
|
||||||
FETCH_PUBLISHED_PAGE_RESOURCES_ERROR: "FETCH_PUBLISHED_PAGE_RESOURCES_ERROR",
|
FETCH_PUBLISHED_PAGE_RESOURCES_ERROR: "FETCH_PUBLISHED_PAGE_RESOURCES_ERROR",
|
||||||
|
PUBLISH_ANVIL_APPLICATION_ERROR: "PUBLISH_ANVIL_APPLICATION_ERROR",
|
||||||
};
|
};
|
||||||
|
|
||||||
const WorkspaceActionTypes = {
|
const WorkspaceActionTypes = {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import {
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
} from "ee/constants/ReduxActionConstants";
|
} from "ee/constants/ReduxActionConstants";
|
||||||
import type {
|
import type {
|
||||||
ApplicationPagePayload,
|
|
||||||
ApplicationResponsePayload,
|
ApplicationResponsePayload,
|
||||||
ChangeAppViewAccessRequest,
|
ChangeAppViewAccessRequest,
|
||||||
CreateApplicationRequest,
|
CreateApplicationRequest,
|
||||||
|
|
@ -29,7 +28,10 @@ import ApplicationApi from "ee/api/ApplicationApi";
|
||||||
import { all, call, put, select, take } from "redux-saga/effects";
|
import { all, call, put, select, take } from "redux-saga/effects";
|
||||||
|
|
||||||
import { validateResponse } from "sagas/ErrorSagas";
|
import { validateResponse } from "sagas/ErrorSagas";
|
||||||
import { getCurrentApplicationIdForCreateNewApp } from "ee/selectors/applicationSelectors";
|
import {
|
||||||
|
getCurrentApplication,
|
||||||
|
getCurrentApplicationIdForCreateNewApp,
|
||||||
|
} from "ee/selectors/applicationSelectors";
|
||||||
import type { ApiResponse } from "api/ApiResponses";
|
import type { ApiResponse } from "api/ApiResponses";
|
||||||
import history from "utils/history";
|
import history from "utils/history";
|
||||||
import type { AppState } from "ee/reducers";
|
import type { AppState } from "ee/reducers";
|
||||||
|
|
@ -103,6 +105,7 @@ import type { IconNames } from "@appsmith/ads";
|
||||||
import {
|
import {
|
||||||
defaultNavigationSetting,
|
defaultNavigationSetting,
|
||||||
keysOfNavigationSetting,
|
keysOfNavigationSetting,
|
||||||
|
type NavigationSetting,
|
||||||
} from "constants/AppConstants";
|
} from "constants/AppConstants";
|
||||||
import { setAllEntityCollapsibleStates } from "actions/editorContextActions";
|
import { setAllEntityCollapsibleStates } from "actions/editorContextActions";
|
||||||
import { getCurrentEnvironmentId } from "ee/selectors/environmentSelectors";
|
import { getCurrentEnvironmentId } from "ee/selectors/environmentSelectors";
|
||||||
|
|
@ -115,18 +118,52 @@ import equal from "fast-deep-equal";
|
||||||
import { getFromServerWhenNoPrefetchedResult } from "sagas/helper";
|
import { getFromServerWhenNoPrefetchedResult } from "sagas/helper";
|
||||||
import type { Page } from "entities/Page";
|
import type { Page } from "entities/Page";
|
||||||
import type { ApplicationPayload } from "entities/Application";
|
import type { ApplicationPayload } from "entities/Application";
|
||||||
|
import { objectKeys } from "@appsmith/utils";
|
||||||
export const findDefaultPage = (pages: ApplicationPagePayload[] = []) => {
|
import { findDefaultPage } from "pages/utils";
|
||||||
const defaultPage = pages.find((page) => page.isDefault) ?? pages[0];
|
|
||||||
|
|
||||||
return defaultPage;
|
|
||||||
};
|
|
||||||
|
|
||||||
export let windowReference: Window | null = null;
|
export let windowReference: Window | null = null;
|
||||||
|
|
||||||
export function* publishApplicationSaga(
|
export function* publishApplicationSaga(
|
||||||
requestAction: ReduxAction<PublishApplicationRequest>,
|
requestAction: ReduxAction<PublishApplicationRequest>,
|
||||||
) {
|
) {
|
||||||
|
const currentApplication: ApplicationPayload | undefined = yield select(
|
||||||
|
getCurrentApplication,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentApplication) {
|
||||||
|
const appName = currentApplication.name;
|
||||||
|
const appId = currentApplication?.id;
|
||||||
|
const pageCount = currentApplication?.pages?.length;
|
||||||
|
const navigationSettingsWithPrefix: Record<
|
||||||
|
string,
|
||||||
|
NavigationSetting[keyof NavigationSetting]
|
||||||
|
> = {};
|
||||||
|
|
||||||
|
if (currentApplication.applicationDetail?.navigationSetting) {
|
||||||
|
const settingKeys = objectKeys(
|
||||||
|
currentApplication.applicationDetail.navigationSetting,
|
||||||
|
) as Array<keyof NavigationSetting>;
|
||||||
|
|
||||||
|
settingKeys.map((key: keyof NavigationSetting) => {
|
||||||
|
if (currentApplication.applicationDetail?.navigationSetting?.[key]) {
|
||||||
|
const value: NavigationSetting[keyof NavigationSetting] =
|
||||||
|
currentApplication.applicationDetail.navigationSetting[key];
|
||||||
|
|
||||||
|
navigationSettingsWithPrefix[`navigationSetting_${key}`] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent("PUBLISH_APP", {
|
||||||
|
appId,
|
||||||
|
appName,
|
||||||
|
pageCount,
|
||||||
|
...navigationSettingsWithPrefix,
|
||||||
|
isPublic: !!currentApplication?.isPublic,
|
||||||
|
templateTitle: currentApplication?.forkedFromTemplateTitle,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const request = requestAction.payload;
|
const request = requestAction.payload;
|
||||||
const response: PublishApplicationResponse = yield call(
|
const response: PublishApplicationResponse = yield call(
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { Button, Tooltip } from "@appsmith/ads";
|
import { Button, Tooltip } from "@appsmith/ads";
|
||||||
import { objectKeys } from "@appsmith/utils";
|
|
||||||
import { showConnectGitModal } from "actions/gitSyncActions";
|
import { showConnectGitModal } from "actions/gitSyncActions";
|
||||||
import { publishApplication } from "ee/actions/applicationActions";
|
import {
|
||||||
import { getCurrentApplication } from "ee/selectors/applicationSelectors";
|
publishAnvilApplication,
|
||||||
import type { NavigationSetting } from "constants/AppConstants";
|
publishApplication,
|
||||||
|
} from "ee/actions/applicationActions";
|
||||||
import {
|
import {
|
||||||
createMessage,
|
createMessage,
|
||||||
DEPLOY_BUTTON_TOOLTIP,
|
DEPLOY_BUTTON_TOOLTIP,
|
||||||
|
|
@ -25,6 +25,7 @@ import {
|
||||||
getIsPublishingApplication,
|
getIsPublishingApplication,
|
||||||
} from "selectors/editorSelectors";
|
} from "selectors/editorSelectors";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import { getIsAnvilEnabledInCurrentApplication } from "layoutSystems/anvil/integrations/selectors";
|
||||||
|
|
||||||
// This wrapper maintains pointer events for tooltips when the child button is disabled.
|
// This wrapper maintains pointer events for tooltips when the child button is disabled.
|
||||||
// Without this, disabled buttons won't trigger tooltips because they have pointer-events: none
|
// Without this, disabled buttons won't trigger tooltips because they have pointer-events: none
|
||||||
|
|
@ -34,7 +35,6 @@ const StyledTooltipTarget = styled.span`
|
||||||
|
|
||||||
function DeployButton() {
|
function DeployButton() {
|
||||||
const applicationId = useSelector(getCurrentApplicationId);
|
const applicationId = useSelector(getCurrentApplicationId);
|
||||||
const currentApplication = useSelector(getCurrentApplication);
|
|
||||||
const isPackageUpgrading = useSelector(getIsPackageUpgrading);
|
const isPackageUpgrading = useSelector(getIsPackageUpgrading);
|
||||||
const isProtectedMode = useGitProtectedMode();
|
const isProtectedMode = useGitProtectedMode();
|
||||||
const isDeployDisabled = isPackageUpgrading || isProtectedMode;
|
const isDeployDisabled = isPackageUpgrading || isProtectedMode;
|
||||||
|
|
@ -49,42 +49,7 @@ function DeployButton() {
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const handlePublish = useCallback(() => {
|
const isAnvilEnabled = useSelector(getIsAnvilEnabledInCurrentApplication);
|
||||||
if (applicationId) {
|
|
||||||
dispatch(publishApplication(applicationId));
|
|
||||||
|
|
||||||
const appName = currentApplication ? currentApplication.name : "";
|
|
||||||
const pageCount = currentApplication?.pages?.length;
|
|
||||||
const navigationSettingsWithPrefix: Record<
|
|
||||||
string,
|
|
||||||
NavigationSetting[keyof NavigationSetting]
|
|
||||||
> = {};
|
|
||||||
|
|
||||||
if (currentApplication?.applicationDetail?.navigationSetting) {
|
|
||||||
const settingKeys = objectKeys(
|
|
||||||
currentApplication.applicationDetail.navigationSetting,
|
|
||||||
) as Array<keyof NavigationSetting>;
|
|
||||||
|
|
||||||
settingKeys.map((key: keyof NavigationSetting) => {
|
|
||||||
if (currentApplication?.applicationDetail?.navigationSetting?.[key]) {
|
|
||||||
const value: NavigationSetting[keyof NavigationSetting] =
|
|
||||||
currentApplication.applicationDetail.navigationSetting[key];
|
|
||||||
|
|
||||||
navigationSettingsWithPrefix[`navigationSetting_${key}`] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
AnalyticsUtil.logEvent("PUBLISH_APP", {
|
|
||||||
appId: applicationId,
|
|
||||||
appName,
|
|
||||||
pageCount,
|
|
||||||
...navigationSettingsWithPrefix,
|
|
||||||
isPublic: !!currentApplication?.isPublic,
|
|
||||||
templateTitle: currentApplication?.forkedFromTemplateTitle,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [applicationId, currentApplication, dispatch]);
|
|
||||||
|
|
||||||
const handleClickDeploy = useCallback(() => {
|
const handleClickDeploy = useCallback(() => {
|
||||||
if (isGitConnected) {
|
if (isGitConnected) {
|
||||||
|
|
@ -97,12 +62,15 @@ function DeployButton() {
|
||||||
AnalyticsUtil.logEvent("GS_DEPLOY_GIT_CLICK", {
|
AnalyticsUtil.logEvent("GS_DEPLOY_GIT_CLICK", {
|
||||||
source: "Deploy button",
|
source: "Deploy button",
|
||||||
});
|
});
|
||||||
|
} else if (isAnvilEnabled) {
|
||||||
|
dispatch(publishAnvilApplication(applicationId));
|
||||||
} else {
|
} else {
|
||||||
handlePublish();
|
dispatch(publishApplication(applicationId));
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
applicationId,
|
||||||
dispatch,
|
dispatch,
|
||||||
handlePublish,
|
isAnvilEnabled,
|
||||||
isGitConnected,
|
isGitConnected,
|
||||||
isGitModEnabled,
|
isGitModEnabled,
|
||||||
toggleOpsModal,
|
toggleOpsModal,
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ import type { Datasource } from "entities/Datasource";
|
||||||
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
||||||
import { useQuery } from "../utils";
|
import { useQuery } from "../utils";
|
||||||
import ListItemWrapper from "./components/DatasourceListItem";
|
import ListItemWrapper from "./components/DatasourceListItem";
|
||||||
import { findDefaultPage } from "ee/sagas/ApplicationSagas";
|
import { findDefaultPage } from "pages/utils";
|
||||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||||
import {
|
import {
|
||||||
getOAuthAccessToken,
|
getOAuthAccessToken,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { getSearchQuery } from "utils/helpers";
|
import { getSearchQuery } from "utils/helpers";
|
||||||
import type { Location } from "history";
|
import type { Location } from "history";
|
||||||
|
import type { ApplicationPagePayload } from "ee/api/ApplicationApi";
|
||||||
|
|
||||||
export const getIsBranchUpdated = (
|
export const getIsBranchUpdated = (
|
||||||
prevLocation: Location<unknown>,
|
prevLocation: Location<unknown>,
|
||||||
|
|
@ -29,3 +30,8 @@ export const removeClassFromDocumentRoot = (className: string) => {
|
||||||
element.classList.remove(className);
|
element.classList.remove(className);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
export const findDefaultPage = (pages: ApplicationPagePayload[] = []) => {
|
||||||
|
const defaultPage = pages.find((page) => page.isDefault) ?? pages[0];
|
||||||
|
|
||||||
|
return defaultPage;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
} from "ee/constants/ReduxActionConstants";
|
} from "ee/constants/ReduxActionConstants";
|
||||||
import urlBuilder from "ee/entities/URLRedirect/URLAssembly";
|
import urlBuilder from "ee/entities/URLRedirect/URLAssembly";
|
||||||
import { findDefaultPage } from "ee/sagas/ApplicationSagas";
|
import { findDefaultPage } from "pages/utils";
|
||||||
import { fetchPageDSLSaga } from "ee/sagas/PageSagas";
|
import { fetchPageDSLSaga } from "ee/sagas/PageSagas";
|
||||||
import { getCurrentWorkspaceId } from "ee/selectors/selectedWorkspaceSelectors";
|
import { getCurrentWorkspaceId } from "ee/selectors/selectedWorkspaceSelectors";
|
||||||
import { isAirgapped } from "ee/utils/airgapHelpers";
|
import { isAirgapped } from "ee/utils/airgapHelpers";
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,6 @@ export const getLastJSTab = (state: AppState): FocusEntityInfo | undefined => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getIsGeneratingSchema = (state: AppState, collectionId: string) =>
|
|
||||||
state.ui.jsPane.isSchemaGenerating[collectionId];
|
|
||||||
|
|
||||||
export const getIsJSCollectionSaving = (
|
export const getIsJSCollectionSaving = (
|
||||||
state: AppState,
|
state: AppState,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user