PromucFlow_constructor/app/client/src/pages/Editor/index.tsx
Rudraprasad Das 9ce2598e76
chore: git mod - integration with applications (#38439)
## Description
- Git mod integration with applications behind feature flag

Fixes #37815 
Fixes #37816 
Fixes #37817 
Fixes #37818 
Fixes #37819 
Fixes #37820 

## Automation

/ok-to-test tags="@tag.All"

### 🔍 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/12570655268>
> Commit: 7d2f1a7013bc2fc6c960699ee0b6e06800cd21f9
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12570655268&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Wed, 01 Jan 2025 14:35:46 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No
2025-01-05 11:21:23 +01:00

270 lines
9.4 KiB
TypeScript

import React, { Component } from "react";
import { Helmet } from "react-helmet";
import { connect } from "react-redux";
import type { RouteComponentProps } from "react-router-dom";
import { withRouter } from "react-router-dom";
import type { BuilderRouteParams } from "constants/routes";
import type { AppState } from "ee/reducers";
import IDE from "./IDE";
import {
getCurrentApplicationId,
getIsEditorInitialized,
getIsEditorLoading,
getIsPublishingApplication,
getPageList,
getPublishingError,
} from "selectors/editorSelectors";
import type { InitEditorActionPayload } from "actions/initActions";
import { initEditorAction, resetEditorRequest } from "actions/initActions";
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import { getCurrentUser } from "selectors/usersSelectors";
import type { User } from "constants/userConstants";
import RequestConfirmationModal from "pages/Editor/RequestConfirmationModal";
import * as Sentry from "@sentry/react";
import { getTheme, ThemeMode } from "selectors/themeSelectors";
import { ThemeProvider } from "styled-components";
import type { Theme } from "constants/DefaultTheme";
import GlobalHotKeys from "./GlobalHotKeys";
import { setupPageAction, updateCurrentPage } from "actions/pageActions";
import { getCurrentPageId } from "selectors/editorSelectors";
import { getSearchQuery } from "utils/helpers";
import ImportedApplicationSuccessModal from "./gitSync/ImportSuccessModal";
import { getIsBranchUpdated } from "../utils";
import { APP_MODE } from "entities/App";
import { GIT_BRANCH_QUERY_KEY } from "constants/routes";
import TemplatesModal from "pages/Templates/TemplatesModal";
import ReconnectDatasourceModal from "./gitSync/ReconnectDatasourceModal";
import { Spinner } from "@appsmith/ads";
import SignpostingOverlay from "pages/Editor/FirstTimeUserOnboarding/Overlay";
import { editorInitializer } from "../../utils/editor/EditorUtils";
import { widgetInitialisationSuccess } from "../../actions/widgetActions";
import urlBuilder from "ee/entities/URLRedirect/URLAssembly";
import { PartialExportModal } from "components/editorComponents/PartialImportExport/PartialExportModal";
import { PartialImportModal } from "components/editorComponents/PartialImportExport/PartialImportModal";
import type { Page } from "entities/Page";
import { AppCURLImportModal } from "ee/pages/Editor/CurlImport";
import { IDE_HEADER_HEIGHT } from "@appsmith/ads";
import GeneratePageModal from "./GeneratePage";
import { GitModals as NewGitModals } from "git";
import GitSyncModal from "./gitSync/GitSyncModal";
import GitSettingsModal from "./gitSync/GitSettingsModal";
import DisconnectGitModal from "./gitSync/DisconnectGitModal";
import DisableAutocommitModal from "./gitSync/DisableAutocommitModal";
import ReconfigureCDKeyModal from "ee/components/gitComponents/ReconfigureCDKeyModal";
import DisableCDModal from "ee/components/gitComponents/DisableCDModal";
import RepoLimitExceededErrorModal from "./gitSync/RepoLimitExceededErrorModal";
import { useGitModEnabled } from "./gitSync/hooks/modHooks";
import GitApplicationContextProvider from "components/gitContexts/GitApplicationContextProvider";
function GitModals() {
const isGitModEnabled = useGitModEnabled();
return isGitModEnabled ? (
<NewGitModals />
) : (
<>
<GitSyncModal />
<GitSettingsModal />
<DisableCDModal />
<ReconfigureCDKeyModal />
<DisconnectGitModal />
<DisableAutocommitModal />
<RepoLimitExceededErrorModal />
</>
);
}
interface EditorProps {
currentApplicationId?: string;
currentApplicationName?: string;
initEditor: (payload: InitEditorActionPayload) => void;
isPublishing: boolean;
isEditorLoading: boolean;
isEditorInitialized: boolean;
isEditorInitializeError: boolean;
errorPublishing: boolean;
loadingGuidedTour: boolean;
user?: User;
lightTheme: Theme;
resetEditorRequest: () => void;
setupPage: (pageId: string) => void;
updateCurrentPage: (pageId: string) => void;
handleBranchChange: (branch: string) => void;
currentPageId?: string;
pageLevelSocketRoomId: string;
isMultiPane: boolean;
widgetConfigBuildSuccess: () => void;
pages: Page[];
}
type Props = EditorProps & RouteComponentProps<BuilderRouteParams>;
class Editor extends Component<Props> {
prevPageId: string | null = null;
componentDidMount() {
const { basePageId } = this.props.match.params || {};
urlBuilder.setCurrentBasePageId(basePageId);
editorInitializer().then(() => {
this.props.widgetConfigBuildSuccess();
});
}
shouldComponentUpdate(nextProps: Props) {
const isBranchUpdated = getIsBranchUpdated(
this.props.location,
nextProps.location,
);
return (
isBranchUpdated ||
nextProps.currentApplicationName !== this.props.currentApplicationName ||
nextProps.match?.params?.basePageId !==
this.props.match?.params?.basePageId ||
nextProps.currentApplicationId !== this.props.currentApplicationId ||
nextProps.isEditorInitialized !== this.props.isEditorInitialized ||
nextProps.isPublishing !== this.props.isPublishing ||
nextProps.isEditorLoading !== this.props.isEditorLoading ||
nextProps.errorPublishing !== this.props.errorPublishing ||
nextProps.isEditorInitializeError !==
this.props.isEditorInitializeError ||
nextProps.loadingGuidedTour !== this.props.loadingGuidedTour
);
}
componentDidUpdate(prevProps: Props) {
const { baseApplicationId, basePageId } = this.props.match.params || {};
const { basePageId: prevBasePageId } = prevProps.match.params || {};
const pageId = this.props.pages.find(
(page) => page.basePageId === basePageId,
)?.pageId;
const prevPageId = prevProps.pages.find(
(page) => page.basePageId === prevBasePageId,
)?.pageId;
// caching value for prevPageId as it is required in future lifecycles
if (prevPageId) {
this.prevPageId = prevPageId;
}
const isPageIdUpdated = pageId !== this.prevPageId;
const isBasePageIdUpdated = basePageId !== prevBasePageId;
const isPageUpdated = isPageIdUpdated || isBasePageIdUpdated;
const isBranchUpdated = getIsBranchUpdated(
this.props.location,
prevProps.location,
);
const branch = getSearchQuery(
this.props.location.search,
GIT_BRANCH_QUERY_KEY,
);
const prevBranch = getSearchQuery(
prevProps.location.search,
GIT_BRANCH_QUERY_KEY,
);
// to prevent re-init during connect
if (prevBranch && isBranchUpdated && basePageId) {
this.props.initEditor({
baseApplicationId,
basePageId,
branch,
mode: APP_MODE.EDIT,
});
} else {
/**
* First time load is handled by init sagas
* If we don't check for `prevPageId`: fetch page is re triggered
* when redirected to the default page
*/
if (pageId && this.prevPageId && isPageUpdated) {
this.props.updateCurrentPage(pageId);
this.props.setupPage(pageId);
urlBuilder.setCurrentBasePageId(basePageId);
}
}
}
componentWillUnmount() {
this.props.resetEditorRequest();
urlBuilder.setCurrentBasePageId(null);
}
public render() {
if (!this.props.isEditorInitialized || this.props.loadingGuidedTour) {
return (
<CenteredWrapper
style={{ height: `calc(100vh - ${IDE_HEADER_HEIGHT}px)` }}
>
<Spinner size="lg" />
</CenteredWrapper>
);
}
return (
<ThemeProvider theme={theme}>
<div>
<Helmet>
<meta charSet="utf-8" />
<title>
{`${this.props.currentApplicationName} | Editor | Appsmith`}
</title>
</Helmet>
<GitApplicationContextProvider>
<GlobalHotKeys>
<IDE />
<GitModals />
<TemplatesModal />
<ImportedApplicationSuccessModal />
<ReconnectDatasourceModal />
<SignpostingOverlay />
<PartialExportModal />
<PartialImportModal />
<AppCURLImportModal />
<GeneratePageModal />
</GlobalHotKeys>
</GitApplicationContextProvider>
</div>
<RequestConfirmationModal />
</ThemeProvider>
);
}
}
const theme = getTheme(ThemeMode.LIGHT);
const mapStateToProps = (state: AppState) => ({
currentApplicationId: getCurrentApplicationId(state),
errorPublishing: getPublishingError(state),
isPublishing: getIsPublishingApplication(state),
isEditorLoading: getIsEditorLoading(state),
isEditorInitialized: getIsEditorInitialized(state),
user: getCurrentUser(state),
currentApplicationName: state.ui.applications.currentApplication?.name,
currentPageId: getCurrentPageId(state),
pages: getPageList(state),
});
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const mapDispatchToProps = (dispatch: any) => {
return {
initEditor: (payload: InitEditorActionPayload) =>
dispatch(initEditorAction(payload)),
resetEditorRequest: () => dispatch(resetEditorRequest()),
setupPage: (pageId: string) => dispatch(setupPageAction({ id: pageId })),
updateCurrentPage: (pageId: string) => dispatch(updateCurrentPage(pageId)),
widgetConfigBuildSuccess: () => dispatch(widgetInitialisationSuccess()),
};
};
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Sentry.withProfiler(Editor)),
);