PromucFlow_constructor/app/client/src/pages/AppViewer/index.tsx
2022-01-25 19:26:52 +05:30

263 lines
7.8 KiB
TypeScript

import React, { Component } from "react";
import styled, { ThemeProvider } from "styled-components";
import { connect } from "react-redux";
import { withRouter, RouteComponentProps, Route } from "react-router";
import { Switch } from "react-router-dom";
import { AppState } from "reducers";
import {
AppViewerRouteParams,
BuilderRouteParams,
GIT_BRANCH_QUERY_KEY,
VIEWER_FORK_PATH,
VIEWER_URL,
} from "constants/routes";
import {
PageListPayload,
ReduxActionTypes,
} from "constants/ReduxActionConstants";
import { getIsInitialized } from "selectors/appViewSelectors";
import { executeTrigger } from "actions/widgetActions";
import { ExecuteTriggerPayload } from "constants/AppsmithActionConstants/ActionConstants";
import {
BatchPropertyUpdatePayload,
batchUpdateWidgetProperty,
updateWidgetPropertyRequest,
} from "actions/controlActions";
import { EditorContext } from "components/editorComponents/EditorContextProvider";
import AppViewerPageContainer from "./AppViewerPageContainer";
import {
resetChildrenMetaProperty,
updateWidgetMetaProperty,
} from "actions/metaActions";
import { editorInitializer } from "utils/EditorUtils";
import * as Sentry from "@sentry/react";
import { getViewModePageList } from "selectors/editorSelectors";
import AddCommentTourComponent from "comments/tour/AddCommentTourComponent";
import CommentShowCaseCarousel from "comments/CommentsShowcaseCarousel";
import { getThemeDetails, ThemeMode } from "selectors/themeSelectors";
import { Theme } from "constants/DefaultTheme";
import GlobalHotKeys from "./GlobalHotKeys";
import { getSearchQuery } from "utils/helpers";
import AppViewerCommentsSidebar from "./AppViewerComemntsSidebar";
import { showPostCompletionMessage } from "selectors/onboardingSelectors";
const SentryRoute = Sentry.withSentryRouting(Route);
const AppViewerBody = styled.section<{
hasPages: boolean;
showGuidedTourMessage: boolean;
isEmbeded: boolean;
}>`
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: flex-start;
height: ${(props) => {
// embeded page will not have top header
if (props.isEmbeded) return "100vh;";
let offsetHeight = "";
if (!props.hasPages) {
offsetHeight = `${props.theme.smallHeaderHeight} - 1px`;
} else {
offsetHeight = "72px";
}
if (props.showGuidedTourMessage) {
offsetHeight += " - 100px";
}
return `calc(100vh - ${offsetHeight});`;
}};
`;
const ContainerWithComments = styled.div`
display: flex;
width: 100%;
height: 100%;
background: ${(props) => props.theme.colors.artboard};
`;
const AppViewerBodyContainer = styled.div<{ width?: string }>`
flex: 1;
overflow: auto;
margin: 0 auto;
`;
export type AppViewerProps = {
initializeAppViewer: (params: {
applicationId: string;
pageId?: string;
branch?: string;
}) => void;
isInitialized: boolean;
showGuidedTourMessage: boolean;
isInitializeError: boolean;
executeAction: (actionPayload: ExecuteTriggerPayload) => void;
updateWidgetProperty: (
widgetId: string,
propertyName: string,
propertyValue: any,
) => void;
updateWidgetMetaProperty: (
widgetId: string,
propertyName: string,
propertyValue: any,
) => void;
resetChildrenMetaProperty: (widgetId: string) => void;
pages: PageListPayload;
lightTheme: Theme;
batchUpdateWidgetProperty: (
widgetId: string,
updates: BatchPropertyUpdatePayload,
) => void;
} & RouteComponentProps<BuilderRouteParams>;
type Props = AppViewerProps & RouteComponentProps<AppViewerRouteParams>;
class AppViewer extends Component<Props> {
public state = {
registered: false,
isSideNavOpen: true,
};
componentDidMount() {
editorInitializer().then(() => {
this.setState({ registered: true });
});
const { applicationId, pageId } = this.props.match.params;
const {
location: { search },
} = this.props;
const branch = getSearchQuery(search, GIT_BRANCH_QUERY_KEY);
if (applicationId) {
this.props.initializeAppViewer({
branch: branch,
applicationId,
pageId,
});
}
}
componentDidUpdate(prevProps: Props) {
const { applicationId, pageId } = this.props.match.params;
const {
location: { search: prevSearch },
} = prevProps;
const {
location: { search },
} = this.props;
const prevBranch = getSearchQuery(prevSearch, GIT_BRANCH_QUERY_KEY);
const branch = getSearchQuery(search, GIT_BRANCH_QUERY_KEY);
if (branch && branch !== prevBranch && applicationId && pageId) {
this.props.initializeAppViewer({
applicationId,
pageId,
branch: branch,
});
}
}
toggleCollapse = (open: boolean) => {
this.setState({ isSideNavOpen: open });
};
public render() {
const { isInitialized, location } = this.props;
const isEmbeded = location.search.indexOf("embed=true") !== -1;
return (
<ThemeProvider theme={this.props.lightTheme}>
<GlobalHotKeys>
<EditorContext.Provider
value={{
executeAction: this.props.executeAction,
updateWidgetMetaProperty: this.props.updateWidgetMetaProperty,
resetChildrenMetaProperty: this.props.resetChildrenMetaProperty,
batchUpdateWidgetProperty: this.props.batchUpdateWidgetProperty,
}}
>
<ContainerWithComments>
<AppViewerCommentsSidebar />
<AppViewerBodyContainer>
<AppViewerBody
hasPages={this.props.pages.length > 1}
isEmbeded={isEmbeded}
showGuidedTourMessage={this.props.showGuidedTourMessage}
>
{isInitialized && this.state.registered && (
<Switch>
<SentryRoute
component={AppViewerPageContainer}
exact
path={VIEWER_URL}
/>
<SentryRoute
component={AppViewerPageContainer}
exact
path={VIEWER_FORK_PATH}
/>
</Switch>
)}
</AppViewerBody>
</AppViewerBodyContainer>
</ContainerWithComments>
<AddCommentTourComponent />
<CommentShowCaseCarousel />
</EditorContext.Provider>
</GlobalHotKeys>
</ThemeProvider>
);
}
}
const mapStateToProps = (state: AppState) => ({
isInitialized: getIsInitialized(state),
pages: getViewModePageList(state),
lightTheme: getThemeDetails(state, ThemeMode.LIGHT),
showGuidedTourMessage: showPostCompletionMessage(state),
});
const mapDispatchToProps = (dispatch: any) => ({
executeAction: (actionPayload: ExecuteTriggerPayload) =>
dispatch(executeTrigger(actionPayload)),
updateWidgetProperty: (
widgetId: string,
propertyName: string,
propertyValue: any,
) =>
dispatch(
updateWidgetPropertyRequest(widgetId, propertyName, propertyValue),
),
updateWidgetMetaProperty: (
widgetId: string,
propertyName: string,
propertyValue: any,
) =>
dispatch(updateWidgetMetaProperty(widgetId, propertyName, propertyValue)),
resetChildrenMetaProperty: (widgetId: string) =>
dispatch(resetChildrenMetaProperty(widgetId)),
initializeAppViewer: (params: {
applicationId: string;
pageId?: string;
branch?: string;
}) => {
dispatch({
type: ReduxActionTypes.INITIALIZE_PAGE_VIEWER,
payload: params,
});
},
batchUpdateWidgetProperty: (
widgetId: string,
updates: BatchPropertyUpdatePayload,
) => dispatch(batchUpdateWidgetProperty(widgetId, updates)),
});
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Sentry.withProfiler(AppViewer)),
);