chore: Transitions for IDE (#35714)
## Description Uses `AnimatedGridLayout` component to introduce transitions for the IDE. This is behind a feature flag Fixes #34538 Fixes #30863 Fixes #34544 ## Automation /ok-to-test tags="@tag.All" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!CAUTION] > 🔴 🔴 🔴 Some tests have failed. > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/10737363879> > Commit: a912f5c52366abe48768727a1c605cd72b48752c > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10737363879&attempt=2&selectiontype=test&testsstatus=failed&specsstatus=fail" target="_blank">Cypress dashboard</a>. > Tags: @tag.All > Spec: > The following are new failures, please fix them before merging the PR: <ol> > <li>cypress/e2e/Regression/ServerSide/OnLoadTests/ExecuteAction_Spec.ts</ol> > <a href="https://internal.appsmith.com/app/cypress-dashboard/identified-flaky-tests-65890b3c81d7400d08fa9ee3?branch=master" target="_blank">List of identified flaky tests</a>. > <hr>Fri, 06 Sep 2024 16:32:30 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 ## Summary by CodeRabbit - **New Features** - Introduced two new layout components: `AnimatedLayout` and `UnanimatedLayout` for improved editor interface structuring. - Added TypeScript type definitions for the DOM View Transitions API to enhance type safety and developer experience. - Implemented custom hooks, `useGridLayoutTemplate` and `useEditorStateLeftPaneWidth`, for dynamic grid management and left pane width calculation in the IDE layout. - **Improvements** - Enhanced layout responsiveness with the addition of dynamic grid management. - Updated the `Editor` component to use a centralized constant for height calculations, improving maintainability and consistency. - Enhanced test accuracy by refining assertions in the Git Branch Protection test suite. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Sagar Khalasi <sagar@appsmith.com>
This commit is contained in:
parent
1b16be896d
commit
60dbda49e7
|
|
@ -36,10 +36,7 @@ describe("Git Branch Protection", { tags: ["@tag.Git"] }, function () {
|
|||
cy.wait("@gitProtectApi").then((res1) => {
|
||||
_.agHelper.GetNClick(_.gitSync._closeGitSettingsModal);
|
||||
expect(res1.response).to.have.property("statusCode", 200);
|
||||
_.agHelper.AssertElementVisibility(
|
||||
AppSidebar.locators.sidebar,
|
||||
false,
|
||||
);
|
||||
_.agHelper.AssertElementAbsence(AppSidebar.locators.sidebar);
|
||||
_.agHelper.AssertElementVisibility(
|
||||
PageLeftPane.locators.selector,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@
|
|||
"@types/codemirror": "^0.0.96",
|
||||
"@types/deep-diff": "^1.0.0",
|
||||
"@types/dom-mediacapture-record": "^1.0.11",
|
||||
"@types/dom-view-transitions": "^1.0.5",
|
||||
"@types/downloadjs": "^1.4.2",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/js-beautify": "^1.13.2",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from "react";
|
||||
import { Divider, Flex } from "@appsmith/ads";
|
||||
import { AppsmithLink } from "pages/Editor/AppsmithLink";
|
||||
import { IDE_HEADER_HEIGHT } from "./constants";
|
||||
|
||||
interface ChildrenProps {
|
||||
children: React.ReactNode | React.ReactNode[];
|
||||
|
|
@ -59,7 +60,7 @@ const Header = (props: ChildrenProps) => {
|
|||
alignItems="center"
|
||||
border="1px solid var(--ads-v2-color-border)"
|
||||
className="t--editor-header"
|
||||
height="40px"
|
||||
height={IDE_HEADER_HEIGHT + "px"}
|
||||
overflow="hidden"
|
||||
width="100%"
|
||||
>
|
||||
|
|
|
|||
1
app/client/src/IDE/Structure/constants.ts
Normal file
1
app/client/src/IDE/Structure/constants.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const IDE_HEADER_HEIGHT = 40;
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
* These are composable components that you can use to spread the content of the header
|
||||
* It is possible to use the IDE Header without using these subsections
|
||||
*/
|
||||
export { IDE_HEADER_HEIGHT } from "./Structure/constants";
|
||||
export { default as IDEHeader } from "./Structure/Header";
|
||||
|
||||
/* ====================================================
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ export const FEATURE_FLAG = {
|
|||
"ab_learnability_discoverability_collapse_all_except_data_enabled",
|
||||
release_layout_conversion_enabled: "release_layout_conversion_enabled",
|
||||
release_anvil_toggle_enabled: "release_anvil_toggle_enabled",
|
||||
release_ide_animations_enabled: "release_ide_animations_enabled",
|
||||
} as const;
|
||||
|
||||
export type FeatureFlag = keyof typeof FEATURE_FLAG;
|
||||
|
|
@ -82,6 +83,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = {
|
|||
ab_learnability_discoverability_collapse_all_except_data_enabled: true,
|
||||
release_layout_conversion_enabled: false,
|
||||
release_anvil_toggle_enabled: false,
|
||||
release_ide_animations_enabled: false,
|
||||
};
|
||||
|
||||
export const AB_TESTING_EVENT_KEYS = {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export function LayoutArea(props: LayoutAreaProps) {
|
|||
>
|
||||
<div
|
||||
style={{
|
||||
minWidth: dimensions?.width || "100%",
|
||||
width: dimensions?.width || "100%",
|
||||
height: "100%",
|
||||
position: "absolute",
|
||||
overflow: "auto",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import { easings } from "@react-spring/web";
|
||||
import type { AnimatedGridUnit } from "./types";
|
||||
|
||||
/** Default rows config. */
|
||||
export const DEFAULT_ROWS: AnimatedGridUnit[] = ["1fr"];
|
||||
|
||||
export const SPRING_ANIMATION_CONFIG = {
|
||||
easing: easings.easeInCirc,
|
||||
duration: 375,
|
||||
friction: 32,
|
||||
mass: 1,
|
||||
tension: 205,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import styled from "styled-components";
|
||||
import { Layers } from "constants/Layers";
|
||||
import { BOTTOM_BAR_HEIGHT } from "./constants";
|
||||
|
||||
export const Container = styled.div`
|
||||
width: 100%;
|
||||
height: ${(props) => props.theme.bottomBarHeight};
|
||||
height: ${BOTTOM_BAR_HEIGHT}px;
|
||||
display: flex;
|
||||
position: fixed;
|
||||
justify-content: space-between;
|
||||
|
|
|
|||
1
app/client/src/components/BottomBar/constants.ts
Normal file
1
app/client/src/components/BottomBar/constants.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const BOTTOM_BAR_HEIGHT = 37;
|
||||
|
|
@ -7,14 +7,18 @@ import { Button } from "@appsmith/ads";
|
|||
import SwitchEnvironment from "ee/components/SwitchEnvironment";
|
||||
import { Container, Wrapper } from "./components";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getCurrentApplicationId } from "selectors/editorSelectors";
|
||||
import {
|
||||
getCurrentApplicationId,
|
||||
previewModeSelector,
|
||||
} from "selectors/editorSelectors";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { softRefreshActions } from "actions/pluginActionActions";
|
||||
import { START_SWITCH_ENVIRONMENT } from "ee/constants/messages";
|
||||
import { getIsAnvilEnabledInCurrentApplication } from "layoutSystems/anvil/integrations/selectors";
|
||||
|
||||
export default function BottomBar({ viewMode }: { viewMode: boolean }) {
|
||||
export default function BottomBar() {
|
||||
const appId = useSelector(getCurrentApplicationId) || "";
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const dispatch = useDispatch();
|
||||
// We check if the current application is an Anvil application.
|
||||
// If it is an Anvil application, we remove the Git features from the bottomBar
|
||||
|
|
@ -28,17 +32,17 @@ export default function BottomBar({ viewMode }: { viewMode: boolean }) {
|
|||
return (
|
||||
<Container>
|
||||
<Wrapper>
|
||||
{!viewMode && (
|
||||
{!isPreviewMode && (
|
||||
<SwitchEnvironment
|
||||
editorId={appId}
|
||||
onChangeEnv={onChangeEnv}
|
||||
startSwitchEnvMessage={START_SWITCH_ENVIRONMENT}
|
||||
viewMode={viewMode}
|
||||
viewMode={isPreviewMode}
|
||||
/>
|
||||
)}
|
||||
{!viewMode && !isAnvilEnabled && <QuickGitActions />}
|
||||
{!isPreviewMode && !isAnvilEnabled && <QuickGitActions />}
|
||||
</Wrapper>
|
||||
{!viewMode && (
|
||||
{!isPreviewMode && (
|
||||
<Wrapper>
|
||||
<ManualUpgrades showTooltip>
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -1,51 +1,28 @@
|
|||
import classNames from "classnames";
|
||||
import React, {
|
||||
memo,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from "react";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { useSelector } from "react-redux";
|
||||
import React, { memo, useContext, useEffect, useMemo, useRef } from "react";
|
||||
|
||||
import { getSelectedWidgets } from "selectors/ui";
|
||||
import { tailwindLayers } from "constants/Layers";
|
||||
import WidgetPropertyPane from "pages/Editor/PropertyPane";
|
||||
import CanvasPropertyPane from "pages/Editor/CanvasPropertyPane";
|
||||
import useHorizontalResize from "utils/hooks/useHorizontalResize";
|
||||
import { getIsDraggingForSelection } from "selectors/canvasSelectors";
|
||||
import MultiSelectPropertyPane from "pages/Editor/MultiSelectPropertyPane";
|
||||
import { getIsDraggingOrResizing } from "selectors/widgetSelectors";
|
||||
import { selectedWidgetsPresentInCanvas } from "selectors/propertyPaneSelectors";
|
||||
import styled from "styled-components";
|
||||
import WalkthroughContext from "components/featureWalkthrough/walkthroughContext";
|
||||
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
|
||||
|
||||
export const PROPERTY_PANE_ID = "t--property-pane-sidebar";
|
||||
|
||||
const StyledResizer = styled.div<{ resizing: boolean }>`
|
||||
${(props) =>
|
||||
props.resizing &&
|
||||
`
|
||||
& > div {
|
||||
background-color: var(--ads-v2-color-outline);
|
||||
}
|
||||
`}
|
||||
:hover {
|
||||
& > div {
|
||||
background-color: var(--ads-v2-color-bg-emphasis);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
width: number;
|
||||
onDragEnd?: () => void;
|
||||
onWidthChange: (width: number) => void;
|
||||
}
|
||||
|
||||
export const PropertyPaneSidebar = memo((props: Props) => {
|
||||
export const PropertyPaneSidebar = memo(() => {
|
||||
const sidebarRef = useRef<HTMLDivElement>(null);
|
||||
const prevSelectedWidgetId = useRef<string | undefined>();
|
||||
|
||||
const { onMouseDown, onMouseUp, onTouchStart, resizing } =
|
||||
useHorizontalResize(sidebarRef, props.onWidthChange, props.onDragEnd, true);
|
||||
|
||||
const selectedWidgetIds = useSelector(getSelectedWidgets);
|
||||
const isDraggingOrResizing = useSelector(getIsDraggingOrResizing);
|
||||
const { isOpened: isWalkthroughOpened, popFeature } =
|
||||
|
|
@ -58,17 +35,10 @@ export const PropertyPaneSidebar = memo((props: Props) => {
|
|||
selectedWidgetIds[0] !== prevSelectedWidgetId.current) ||
|
||||
selectedWidgetIds[0] === MAIN_CONTAINER_WIDGET_ID;
|
||||
|
||||
// This is to keep the theming properties from changing,
|
||||
// while dragging a widget when no other widgets were selected
|
||||
const keepThemeWhileDragging =
|
||||
prevSelectedWidgetId.current === undefined && shouldNotRenderPane;
|
||||
|
||||
const selectedWidgetsLength = useSelector(
|
||||
(state) => selectedWidgetsPresentInCanvas(state).length,
|
||||
);
|
||||
|
||||
const isDraggingForSelection = useSelector(getIsDraggingForSelection);
|
||||
|
||||
prevSelectedWidgetId.current =
|
||||
selectedWidgetIds.length === 1 ? selectedWidgetIds[0] : undefined;
|
||||
|
||||
|
|
@ -91,27 +61,24 @@ export const PropertyPaneSidebar = memo((props: Props) => {
|
|||
default:
|
||||
return <CanvasPropertyPane />;
|
||||
}
|
||||
}, [
|
||||
selectedWidgetsLength,
|
||||
isDraggingForSelection,
|
||||
shouldNotRenderPane,
|
||||
keepThemeWhileDragging,
|
||||
]);
|
||||
}, [selectedWidgetsLength, shouldNotRenderPane]);
|
||||
|
||||
const closeWalkthrough = () => {
|
||||
const closeWalkthrough = useCallback(() => {
|
||||
if (popFeature) {
|
||||
popFeature("PROPERTY_PANE");
|
||||
sidebarRef.current?.removeEventListener("click", closeWalkthrough);
|
||||
}
|
||||
};
|
||||
}, [popFeature]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isWalkthroughOpened)
|
||||
sidebarRef.current?.addEventListener("click", closeWalkthrough);
|
||||
const currentSidebar = sidebarRef.current;
|
||||
if (isWalkthroughOpened) {
|
||||
currentSidebar?.addEventListener("click", closeWalkthrough);
|
||||
}
|
||||
return () => {
|
||||
sidebarRef.current?.removeEventListener("click", closeWalkthrough);
|
||||
currentSidebar?.removeEventListener("click", closeWalkthrough);
|
||||
};
|
||||
}, [isWalkthroughOpened]);
|
||||
}, [closeWalkthrough, isWalkthroughOpened]);
|
||||
|
||||
return (
|
||||
<div className="relative h-full">
|
||||
|
|
@ -122,28 +89,7 @@ export const PropertyPaneSidebar = memo((props: Props) => {
|
|||
id={PROPERTY_PANE_ID}
|
||||
ref={sidebarRef}
|
||||
>
|
||||
{/* RESIZER */}
|
||||
<StyledResizer
|
||||
className={`absolute top-0 left-0 w-2 h-full -ml-1 group cursor-ew-resize ${tailwindLayers.resizer}`}
|
||||
onMouseDown={onMouseDown}
|
||||
onTouchEnd={onMouseUp}
|
||||
onTouchStart={onTouchStart}
|
||||
resizing={resizing}
|
||||
>
|
||||
<div
|
||||
className={classNames({
|
||||
"w-1 h-full bg-transparent transform transition flex items-center":
|
||||
true,
|
||||
})}
|
||||
/>
|
||||
</StyledResizer>
|
||||
<div
|
||||
className={classNames({
|
||||
"h-full p-0 overflow-y-auto min-w-72 max-w-104": true,
|
||||
"transition-all duration-400": !resizing,
|
||||
})}
|
||||
style={{ width: props.width }}
|
||||
>
|
||||
<div className={"h-full p-0 overflow-y-auto min-w-72 max-w-104 w-full"}>
|
||||
{propertyPane}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import React, { useEffect, useState } from "react";
|
|||
import type { ReactNode } from "react";
|
||||
import styled from "styled-components";
|
||||
import { Layers } from "constants/Layers";
|
||||
import { theme } from "constants/DefaultTheme";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { getAppViewHeaderHeight } from "selectors/appViewSelectors";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import { useMaxModalWidth } from "widgets/ModalWidget/component/useModalWidth";
|
||||
import { useAppViewerSidebarProperties } from "utils/hooks/useAppViewerSidebarProperties";
|
||||
|
||||
const Container = styled.div<{
|
||||
width?: number;
|
||||
height?: number;
|
||||
|
|
@ -22,7 +22,6 @@ const Container = styled.div<{
|
|||
minSize?: number;
|
||||
isEditMode?: boolean;
|
||||
headerHeight?: number;
|
||||
smallHeaderHeight?: string;
|
||||
leftSidebarWidth?: string;
|
||||
}>`
|
||||
&&& {
|
||||
|
|
@ -152,7 +151,6 @@ export function ModalOverlayLayer(props: BaseWidgetProps) {
|
|||
maxWidth={maxModalWidth}
|
||||
minSize={props.minSize}
|
||||
right={props.bottom}
|
||||
smallHeaderHeight={theme.smallHeaderHeight}
|
||||
top={props.top}
|
||||
width={props.width}
|
||||
zIndex={
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import styled from "styled-components";
|
||||
import { Classes } from "@blueprintjs/core";
|
||||
import { Link, Text } from "@appsmith/ads";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
flex-basis: calc(100% - ${(props) => props.theme.homePage.leftPane.width}px);
|
||||
|
|
@ -37,7 +38,7 @@ export const BottomSpace = styled.div`
|
|||
export const ContentWrapper = styled.div``;
|
||||
|
||||
export const LoaderContainer = styled.div`
|
||||
height: ${(props) => `calc(100vh - ${props.theme.smallHeaderHeight})`};
|
||||
height: calc(100vh - ${IDE_HEADER_HEIGHT}px);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -30,11 +30,12 @@ import {
|
|||
StyledMenuContainer,
|
||||
StyledSidebar,
|
||||
} from "./Sidebar.styled";
|
||||
import { getCurrentThemeDetails } from "selectors/themeSelectors";
|
||||
import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors";
|
||||
import NavigationLogo from "ee/pages/AppViewer/NavigationLogo";
|
||||
import MenuItemContainer from "./components/MenuItemContainer";
|
||||
import BackToAppsButton from "./components/BackToAppsButton";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
import { BOTTOM_BAR_HEIGHT } from "components/BottomBar/constants";
|
||||
|
||||
interface SidebarProps {
|
||||
currentApplicationDetails?: ApplicationPayload;
|
||||
|
|
@ -80,7 +81,6 @@ export function Sidebar(props: SidebarProps) {
|
|||
const isPinned = useSelector(getAppSidebarPinned);
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const { x } = useMouse();
|
||||
const theme = useSelector(getCurrentThemeDetails);
|
||||
const isPreviewMode = useSelector(combinedPreviewModeSelector);
|
||||
const isAppSettingsPaneWithNavigationTabOpen = useSelector(
|
||||
getIsAppSettingsPaneWithNavigationTabOpen,
|
||||
|
|
@ -127,10 +127,10 @@ export function Sidebar(props: SidebarProps) {
|
|||
const suffix = ")";
|
||||
|
||||
if (isPreviewMode) {
|
||||
prefix += `${theme.smallHeaderHeight} - ${theme.bottomBarHeight}`;
|
||||
prefix += `${IDE_HEADER_HEIGHT}px - ${BOTTOM_BAR_HEIGHT}px`;
|
||||
} else if (isAppSettingsPaneWithNavigationTabOpen) {
|
||||
// We deduct 64px as well since it is the margin coming from "m-8" class from tailwind
|
||||
prefix += `${theme.smallHeaderHeight} - ${theme.bottomBarHeight} - 64px`;
|
||||
prefix += `${IDE_HEADER_HEIGHT}px - ${BOTTOM_BAR_HEIGHT}px - 64px`;
|
||||
} else {
|
||||
prefix += "0px";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ const Canvas = (props: CanvasProps) => {
|
|||
<Wrapper
|
||||
$enableMainCanvasResizer={!!props.enableMainCanvasResizer}
|
||||
background={isAnvilLayout ? "" : backgroundForCanvas}
|
||||
className={`relative t--canvas-artboard ${paddingBottomClass} transition-all duration-400 ${marginHorizontalClass} ${getViewportClassName(
|
||||
className={`relative t--canvas-artboard ${paddingBottomClass} ${marginHorizontalClass} ${getViewportClassName(
|
||||
canvasWidth,
|
||||
)}`}
|
||||
data-testid={"t--canvas-artboard"}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import styled from "styled-components";
|
|||
import { Classes } from "@blueprintjs/core";
|
||||
import { getTypographyByKey } from "@appsmith/ads-old";
|
||||
import { Icon } from "@appsmith/ads";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
|
||||
export const Container = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -10,7 +11,7 @@ export const Container = styled.div`
|
|||
background-color: var(--ads-v2-color-bg-subtle);
|
||||
}
|
||||
& .${Classes.EDITABLE_TEXT} {
|
||||
height: ${(props) => props.theme.smallHeaderHeight} !important;
|
||||
height: ${IDE_HEADER_HEIGHT} !important;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
@ -21,9 +22,9 @@ export const Container = styled.div`
|
|||
&&&& .${Classes.EDITABLE_TEXT_CONTENT}, &&&& .${Classes.EDITABLE_TEXT_INPUT} {
|
||||
display: block;
|
||||
${getTypographyByKey("h5")};
|
||||
line-height: ${(props) => props.theme.smallHeaderHeight} !important;
|
||||
line-height: ${IDE_HEADER_HEIGHT} !important;
|
||||
padding: 0 ${(props) => props.theme.spaces[2]}px;
|
||||
height: ${(props) => props.theme.smallHeaderHeight} !important;
|
||||
height: ${IDE_HEADER_HEIGHT} !important;
|
||||
}
|
||||
&&&& .${Classes.EDITABLE_TEXT_INPUT} {
|
||||
margin-right: 20px;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
|
|||
import {
|
||||
APP_SIDEBAR_WIDTH,
|
||||
DEFAULT_EXPLORER_PANE_WIDTH,
|
||||
} from "../../../../constants/AppConstants";
|
||||
} from "constants/AppConstants";
|
||||
import { BOTTOM_BAR_HEIGHT } from "components/BottomBar/constants";
|
||||
|
||||
const BindingContainerMaxHeight = 300;
|
||||
const EntityHeight = 36;
|
||||
const BottomBarHeight = 34;
|
||||
|
||||
const EntityInfoContainer = styled.div`
|
||||
min-width: 220px;
|
||||
|
|
@ -108,7 +108,7 @@ export function EntityProperties() {
|
|||
let bottom;
|
||||
if (
|
||||
top + BindingContainerMaxHeight >
|
||||
window.innerHeight - BottomBarHeight
|
||||
window.innerHeight - BOTTOM_BAR_HEIGHT
|
||||
) {
|
||||
bottom = window.innerHeight - rect?.bottom - EntityHeight;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,14 @@ import { QueryEditor } from "./Query";
|
|||
import EditorTabs from "../EditorTabs";
|
||||
import { useCurrentEditorState } from "../hooks";
|
||||
import { EditorEntityTab } from "ee/entities/IDE/constants";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Container = styled(Flex)`
|
||||
// Animating using https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
|
||||
& {
|
||||
view-transition-name: editor-pane;
|
||||
}
|
||||
`;
|
||||
|
||||
const Editor = () => {
|
||||
const { path } = useRouteMatch();
|
||||
|
|
@ -19,7 +27,7 @@ const Editor = () => {
|
|||
return null;
|
||||
}
|
||||
return (
|
||||
<Flex
|
||||
<Container
|
||||
className="relative"
|
||||
flex={1}
|
||||
flexDirection="column"
|
||||
|
|
@ -37,7 +45,7 @@ const Editor = () => {
|
|||
path={querySegmentRoutes.map((route) => `${path}${route}`)}
|
||||
/>
|
||||
</Switch>
|
||||
</Flex>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React from "react";
|
||||
import { Flex } from "@appsmith/ads";
|
||||
import { useEditorPaneWidth } from "../hooks";
|
||||
import EditorPaneExplorer from "./Explorer";
|
||||
import Editor from "./Editor";
|
||||
import { useSelector } from "react-redux";
|
||||
|
|
@ -9,7 +8,6 @@ import { EditorViewMode } from "ee/entities/IDE/constants";
|
|||
import EntityProperties from "pages/Editor/Explorer/Entity/EntityProperties";
|
||||
|
||||
const EditorPane = () => {
|
||||
const width = useEditorPaneWidth();
|
||||
const ideViewMode = useSelector(getIDEViewMode);
|
||||
|
||||
return (
|
||||
|
|
@ -26,7 +24,7 @@ const EditorPane = () => {
|
|||
// @ts-expect-error Fix this the next time the file is edited
|
||||
gap="spacing-2"
|
||||
height="100%"
|
||||
width={width}
|
||||
width={"100%"}
|
||||
>
|
||||
{/** Entity Properties component is necessary to render
|
||||
the Bindings popover in the context menu.
|
||||
|
|
|
|||
|
|
@ -11,24 +11,48 @@ import {
|
|||
createMessage,
|
||||
} from "ee/constants/messages";
|
||||
import { setIdeEditorViewMode } from "actions/ideActions";
|
||||
import type { AppState } from "ee/reducers";
|
||||
import { selectFeatureFlagCheck } from "ee/selectors/featureFlagsSelectors";
|
||||
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||
|
||||
export const ScreenModeToggle = () => {
|
||||
const dispatch = useDispatch();
|
||||
const ideViewMode = useSelector(getIDEViewMode);
|
||||
const isAnimatedIDEEnabled = useSelector((state: AppState) => {
|
||||
return selectFeatureFlagCheck(
|
||||
state,
|
||||
FEATURE_FLAG.release_ide_animations_enabled,
|
||||
);
|
||||
});
|
||||
|
||||
const switchToFullScreen = useCallback(() => {
|
||||
AnalyticsUtil.logEvent("EDITOR_MODE_CHANGE", {
|
||||
to: EditorViewMode.FullScreen,
|
||||
});
|
||||
dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen));
|
||||
}, [dispatch]);
|
||||
|
||||
// Animating using https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
|
||||
// this has limited availability right now
|
||||
if ("startViewTransition" in document && isAnimatedIDEEnabled) {
|
||||
document.startViewTransition(() => {
|
||||
dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen));
|
||||
});
|
||||
} else {
|
||||
dispatch(setIdeEditorViewMode(EditorViewMode.FullScreen));
|
||||
}
|
||||
}, [dispatch, isAnimatedIDEEnabled]);
|
||||
|
||||
const switchToSplitScreen = useCallback(() => {
|
||||
AnalyticsUtil.logEvent("EDITOR_MODE_CHANGE", {
|
||||
to: EditorViewMode.SplitScreen,
|
||||
});
|
||||
dispatch(setIdeEditorViewMode(EditorViewMode.SplitScreen));
|
||||
}, [dispatch]);
|
||||
if ("startViewTransition" in document && isAnimatedIDEEnabled) {
|
||||
document.startViewTransition(() => {
|
||||
dispatch(setIdeEditorViewMode(EditorViewMode.SplitScreen));
|
||||
});
|
||||
} else {
|
||||
dispatch(setIdeEditorViewMode(EditorViewMode.SplitScreen));
|
||||
}
|
||||
}, [dispatch, isAnimatedIDEEnabled]);
|
||||
|
||||
if (ideViewMode === EditorViewMode.SplitScreen) {
|
||||
return (
|
||||
|
|
|
|||
51
app/client/src/pages/Editor/IDE/Layout/AnimatedLayout.tsx
Normal file
51
app/client/src/pages/Editor/IDE/Layout/AnimatedLayout.tsx
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import React from "react";
|
||||
import { useGridLayoutTemplate } from "./hooks/useGridLayoutTemplate";
|
||||
import EditorWrapperContainer from "pages/Editor/commons/EditorWrapperContainer";
|
||||
import { AnimatedGridLayout, LayoutArea } from "components/AnimatedGridLayout";
|
||||
import { useSelector } from "react-redux";
|
||||
import BottomBar from "components/BottomBar";
|
||||
import Sidebar from "../Sidebar";
|
||||
import LeftPane from "../LeftPane";
|
||||
import MainPane from "../MainPane";
|
||||
import RightPane from "../RightPane";
|
||||
import { Areas } from "./constants";
|
||||
import ProtectedCallout from "../ProtectedCallout";
|
||||
import { protectedModeSelector } from "selectors/gitSyncSelectors";
|
||||
|
||||
function AnimatedLayout() {
|
||||
const isProtectedMode = useSelector(protectedModeSelector);
|
||||
const { areas, columns, rows } = useGridLayoutTemplate();
|
||||
if (columns.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{isProtectedMode && <ProtectedCallout />}
|
||||
<EditorWrapperContainer>
|
||||
<AnimatedGridLayout
|
||||
areas={areas}
|
||||
columns={columns}
|
||||
height="100%"
|
||||
rows={rows}
|
||||
width="100vw"
|
||||
>
|
||||
<LayoutArea name={Areas.Sidebar}>
|
||||
<Sidebar />
|
||||
</LayoutArea>
|
||||
<LayoutArea name={Areas.Explorer}>
|
||||
<LeftPane />
|
||||
</LayoutArea>
|
||||
<LayoutArea name={Areas.WidgetEditor}>
|
||||
<MainPane id="app-body" />
|
||||
</LayoutArea>
|
||||
<LayoutArea name={Areas.PropertyPane}>
|
||||
<RightPane />
|
||||
</LayoutArea>
|
||||
</AnimatedGridLayout>
|
||||
</EditorWrapperContainer>
|
||||
<BottomBar />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export { AnimatedLayout };
|
||||
67
app/client/src/pages/Editor/IDE/Layout/UnanimatedLayout.tsx
Normal file
67
app/client/src/pages/Editor/IDE/Layout/UnanimatedLayout.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import BottomBar from "components/BottomBar";
|
||||
import EditorWrapperContainer from "../../commons/EditorWrapperContainer";
|
||||
import Sidebar from "pages/Editor/IDE/Sidebar";
|
||||
import LeftPane from "../LeftPane";
|
||||
import MainPane from "../MainPane";
|
||||
import RightPane from "../RightPane";
|
||||
import { protectedModeSelector } from "selectors/gitSyncSelectors";
|
||||
import ProtectedCallout from "../ProtectedCallout";
|
||||
import { useGridLayoutTemplate } from "./hooks/useGridLayoutTemplate";
|
||||
import styled from "styled-components";
|
||||
import { Areas } from "./constants";
|
||||
|
||||
const GridContainer = styled.div`
|
||||
display: grid;
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
const LayoutContainer = styled.div<{ name: string }>`
|
||||
position: relative;
|
||||
grid-area: ${(props) => props.name};
|
||||
`;
|
||||
|
||||
function UnanimatedLayout() {
|
||||
const isProtectedMode = useSelector(protectedModeSelector);
|
||||
const { areas, columns } = useGridLayoutTemplate();
|
||||
|
||||
const isSidebarVisible = columns[0] !== "0px";
|
||||
|
||||
return (
|
||||
<>
|
||||
{isProtectedMode && <ProtectedCallout />}
|
||||
<EditorWrapperContainer>
|
||||
<GridContainer
|
||||
style={{
|
||||
gridTemplateRows: "100%",
|
||||
gridTemplateAreas: areas
|
||||
.map((area) => `"${area.join(" ")}"`)
|
||||
.join("\n"),
|
||||
gridTemplateColumns: columns.join(" "),
|
||||
}}
|
||||
>
|
||||
<LayoutContainer name={Areas.Sidebar}>
|
||||
{isSidebarVisible ? <Sidebar /> : <div />}
|
||||
</LayoutContainer>
|
||||
<LayoutContainer name={Areas.Explorer}>
|
||||
<LeftPane />
|
||||
</LayoutContainer>
|
||||
<LayoutContainer name={Areas.WidgetEditor}>
|
||||
<MainPane id="app-body" />
|
||||
</LayoutContainer>
|
||||
<LayoutContainer name={Areas.PropertyPane}>
|
||||
<RightPane />
|
||||
</LayoutContainer>
|
||||
</GridContainer>
|
||||
</EditorWrapperContainer>
|
||||
<BottomBar />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const MemoUanimatedLayout = React.memo(UnanimatedLayout);
|
||||
|
||||
export { MemoUanimatedLayout as UnanimatedLayout };
|
||||
15
app/client/src/pages/Editor/IDE/Layout/constants.ts
Normal file
15
app/client/src/pages/Editor/IDE/Layout/constants.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { APP_SIDEBAR_WIDTH } from "constants/AppConstants";
|
||||
import type { AnimatedGridUnit } from "components/AnimatedGridLayout";
|
||||
|
||||
export const Areas = {
|
||||
Sidebar: "Sidebar",
|
||||
Explorer: "Explorer",
|
||||
CodeEditor: "CodeEditor",
|
||||
WidgetEditor: "WidgetEditor",
|
||||
PropertyPane: "PropertyPane",
|
||||
BottomBar: "BottomBar",
|
||||
} as const;
|
||||
|
||||
export type Area = keyof typeof Areas;
|
||||
|
||||
export const SIDEBAR_WIDTH = (APP_SIDEBAR_WIDTH + "px") as AnimatedGridUnit;
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import useWindowDimensions from "utils/hooks/useWindowDimensions";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
APP_SIDEBAR_WIDTH,
|
||||
DEFAULT_EXPLORER_PANE_WIDTH,
|
||||
SPLIT_SCREEN_RATIO,
|
||||
} from "constants/AppConstants";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getIDEViewMode } from "selectors/ideSelectors";
|
||||
import { getPropertyPaneWidth } from "selectors/propertyPaneSelectors";
|
||||
import { EditorEntityTab, EditorViewMode } from "ee/entities/IDE/constants";
|
||||
import { useCurrentEditorState } from "../../hooks";
|
||||
import { previewModeSelector } from "selectors/editorSelectors";
|
||||
import { protectedModeSelector } from "selectors/gitSyncSelectors";
|
||||
|
||||
export const useEditorStateLeftPaneWidth = (): number => {
|
||||
const [windowWidth] = useWindowDimensions();
|
||||
const [width, setWidth] = useState(windowWidth - APP_SIDEBAR_WIDTH);
|
||||
const editorMode = useSelector(getIDEViewMode);
|
||||
const { segment } = useCurrentEditorState();
|
||||
const propertyPaneWidth = useSelector(getPropertyPaneWidth);
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const isProtectedMode = useSelector(protectedModeSelector);
|
||||
useEffect(
|
||||
function updateWidth() {
|
||||
if (isPreviewMode || isProtectedMode) {
|
||||
setWidth(0);
|
||||
} else if (segment !== EditorEntityTab.UI) {
|
||||
if (editorMode === EditorViewMode.SplitScreen) {
|
||||
setWidth(windowWidth * SPLIT_SCREEN_RATIO);
|
||||
} else {
|
||||
setWidth(windowWidth - APP_SIDEBAR_WIDTH);
|
||||
}
|
||||
} else {
|
||||
setWidth(DEFAULT_EXPLORER_PANE_WIDTH);
|
||||
}
|
||||
},
|
||||
[
|
||||
editorMode,
|
||||
segment,
|
||||
propertyPaneWidth,
|
||||
windowWidth,
|
||||
isPreviewMode,
|
||||
isProtectedMode,
|
||||
],
|
||||
);
|
||||
|
||||
return width;
|
||||
};
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
import React from "react";
|
||||
import type { AnimatedGridUnit } from "components/AnimatedGridLayout";
|
||||
import { useSelector } from "react-redux";
|
||||
import useWindowDimensions from "utils/hooks/useWindowDimensions";
|
||||
import { useCurrentAppState, useCurrentEditorState } from "../../hooks";
|
||||
import { getPropertyPaneWidth } from "selectors/propertyPaneSelectors";
|
||||
import { previewModeSelector } from "selectors/editorSelectors";
|
||||
import { getIDEViewMode } from "selectors/ideSelectors";
|
||||
import { protectedModeSelector } from "selectors/gitSyncSelectors";
|
||||
import {
|
||||
EditorEntityTab,
|
||||
EditorState,
|
||||
EditorViewMode,
|
||||
} from "ee/entities/IDE/constants";
|
||||
import {
|
||||
APP_SETTINGS_PANE_WIDTH,
|
||||
APP_SIDEBAR_WIDTH,
|
||||
} from "constants/AppConstants";
|
||||
import { useEditorStateLeftPaneWidth } from "./useEditorStateLeftPaneWidth";
|
||||
import { type Area, Areas, SIDEBAR_WIDTH } from "../constants";
|
||||
|
||||
interface ReturnValue {
|
||||
areas: Area[][];
|
||||
rows: AnimatedGridUnit[];
|
||||
columns: AnimatedGridUnit[];
|
||||
}
|
||||
|
||||
function useGridLayoutTemplate(): ReturnValue {
|
||||
const areas = React.useMemo(function initialiseAreas() {
|
||||
return [
|
||||
[Areas.Sidebar, Areas.Explorer, Areas.WidgetEditor, Areas.PropertyPane],
|
||||
];
|
||||
}, []);
|
||||
const [columns, setColumns] = React.useState<AnimatedGridUnit[]>([]);
|
||||
const [rows] = React.useState<AnimatedGridUnit[]>(["1fr"]);
|
||||
|
||||
const [windowWidth] = useWindowDimensions();
|
||||
const editorStateLeftPaneWidth = useEditorStateLeftPaneWidth();
|
||||
const PropertyPaneWidth = useSelector(getPropertyPaneWidth);
|
||||
const { segment } = useCurrentEditorState();
|
||||
const appState = useCurrentAppState();
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const editorMode = useSelector(getIDEViewMode);
|
||||
const isProtectedMode = useSelector(protectedModeSelector);
|
||||
|
||||
React.useEffect(
|
||||
function updateIDEColumns() {
|
||||
switch (appState) {
|
||||
case EditorState.DATA:
|
||||
if (isPreviewMode || isProtectedMode) {
|
||||
setColumns([
|
||||
"0px",
|
||||
"0px",
|
||||
(windowWidth + "px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
} else {
|
||||
setColumns([
|
||||
SIDEBAR_WIDTH,
|
||||
"300px",
|
||||
(windowWidth - 300 - 50 + "px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
}
|
||||
|
||||
break;
|
||||
case EditorState.SETTINGS:
|
||||
if (isPreviewMode || isProtectedMode) {
|
||||
setColumns([
|
||||
"0px",
|
||||
"0px",
|
||||
(windowWidth + "px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
} else {
|
||||
setColumns([
|
||||
SIDEBAR_WIDTH,
|
||||
(APP_SETTINGS_PANE_WIDTH + "px") as AnimatedGridUnit,
|
||||
(windowWidth -
|
||||
APP_SIDEBAR_WIDTH -
|
||||
APP_SETTINGS_PANE_WIDTH +
|
||||
"px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case EditorState.LIBRARIES:
|
||||
if (isPreviewMode || isProtectedMode) {
|
||||
setColumns([
|
||||
"0px",
|
||||
"0px",
|
||||
(windowWidth + "px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
} else {
|
||||
setColumns([
|
||||
SIDEBAR_WIDTH,
|
||||
"255px",
|
||||
(windowWidth -
|
||||
APP_SIDEBAR_WIDTH -
|
||||
255 +
|
||||
"px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case EditorState.EDITOR:
|
||||
if (isPreviewMode || isProtectedMode) {
|
||||
setColumns([
|
||||
"0px",
|
||||
(editorStateLeftPaneWidth + "px") as AnimatedGridUnit,
|
||||
(windowWidth + "px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
} else if (segment !== EditorEntityTab.UI) {
|
||||
if (editorMode === EditorViewMode.SplitScreen) {
|
||||
setColumns([
|
||||
SIDEBAR_WIDTH,
|
||||
(editorStateLeftPaneWidth + "px") as AnimatedGridUnit,
|
||||
(windowWidth -
|
||||
APP_SIDEBAR_WIDTH -
|
||||
editorStateLeftPaneWidth +
|
||||
"px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
]);
|
||||
} else {
|
||||
setColumns([
|
||||
SIDEBAR_WIDTH,
|
||||
(editorStateLeftPaneWidth + "px") as AnimatedGridUnit,
|
||||
"0px",
|
||||
"0px",
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
setColumns([
|
||||
SIDEBAR_WIDTH,
|
||||
(editorStateLeftPaneWidth + "px") as AnimatedGridUnit,
|
||||
(windowWidth -
|
||||
APP_SIDEBAR_WIDTH -
|
||||
editorStateLeftPaneWidth -
|
||||
PropertyPaneWidth +
|
||||
1 +
|
||||
"px") as AnimatedGridUnit,
|
||||
(PropertyPaneWidth + 1 + "px") as AnimatedGridUnit,
|
||||
]);
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
appState,
|
||||
isPreviewMode,
|
||||
isProtectedMode,
|
||||
editorStateLeftPaneWidth,
|
||||
PropertyPaneWidth,
|
||||
segment,
|
||||
editorMode,
|
||||
windowWidth,
|
||||
],
|
||||
);
|
||||
|
||||
return { areas, columns, rows };
|
||||
}
|
||||
|
||||
export { useGridLayoutTemplate };
|
||||
2
app/client/src/pages/Editor/IDE/Layout/index.ts
Normal file
2
app/client/src/pages/Editor/IDE/Layout/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { AnimatedLayout } from "./AnimatedLayout";
|
||||
export { UnanimatedLayout } from "./UnanimatedLayout";
|
||||
|
|
@ -98,7 +98,7 @@ const DataSidePane = (props: DataSidePaneProps) => {
|
|||
borderRight="1px solid var(--ads-v2-color-border)"
|
||||
flexDirection="column"
|
||||
height="100%"
|
||||
width="300px"
|
||||
width="100%"
|
||||
>
|
||||
<PaneHeader
|
||||
rightIcon={
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { selectLibrariesForExplorer } from "ee/selectors/entitiesSelector";
|
|||
import { animated, useTransition } from "react-spring";
|
||||
import { LibraryEntity } from "pages/Editor/Explorer/Libraries";
|
||||
import { Flex } from "@appsmith/ads";
|
||||
import { DEFAULT_EXPLORER_PANE_WIDTH } from "constants/AppConstants";
|
||||
|
||||
const LibrarySidePane = () => {
|
||||
const libraries = useSelector(selectLibrariesForExplorer);
|
||||
|
|
@ -21,7 +20,7 @@ const LibrarySidePane = () => {
|
|||
borderRight="1px solid var(--ads-v2-color-border)"
|
||||
flexDirection="column"
|
||||
height="100%"
|
||||
width={DEFAULT_EXPLORER_PANE_WIDTH + "px"}
|
||||
width={"100%"}
|
||||
>
|
||||
<PaneHeader
|
||||
rightIcon={<AddLibraryPopover />}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export const LeftPaneContainer = styled.div<{ showRightBorder?: boolean }>`
|
|||
border-right: ${({ showRightBorder = true }) =>
|
||||
showRightBorder ? "1px solid var(--ads-v2-color-border)" : "none"};
|
||||
background: var(--ads-v2-color-bg);
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const LeftPane = () => {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const MainPane = (props: { id: string }) => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="relative flex flex-col flex-1 overflow-auto z-2"
|
||||
className="relative flex flex-col flex-1 overflow-auto z-2 h-full"
|
||||
data-testid="t--ide-main-pane"
|
||||
id={props.id}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -7,12 +7,15 @@ import IDE from ".";
|
|||
import { BrowserRouter } from "react-router-dom";
|
||||
import "@testing-library/jest-dom";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import store from "store";
|
||||
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const getMockStore = (override: Record<string, any> = {}): any => {
|
||||
const initialState = store.getState();
|
||||
const slice = {
|
||||
ui: {
|
||||
...initialState.ui,
|
||||
applications: {
|
||||
currentApplication: {
|
||||
gitApplicationMetadata: {
|
||||
|
|
@ -32,6 +35,7 @@ const getMockStore = (override: Record<string, any> = {}): any => {
|
|||
const mockStore = configureStore([]);
|
||||
const newSlice = merge(slice, override);
|
||||
return mockStore({
|
||||
...initialState,
|
||||
...newSlice,
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@ import {
|
|||
createMessage,
|
||||
} from "ee/constants/messages";
|
||||
|
||||
export const PROTECTED_CALLOUT_HEIGHT = 70;
|
||||
|
||||
const StyledCallout = styled(Callout)`
|
||||
height: 70px;
|
||||
height: ${PROTECTED_CALLOUT_HEIGHT}px;
|
||||
overflow-y: hidden;
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,10 @@ import {
|
|||
EditorEntityTab,
|
||||
EditorEntityTabState,
|
||||
EditorState,
|
||||
EditorViewMode,
|
||||
} from "ee/entities/IDE/constants";
|
||||
import { useLocation } from "react-router";
|
||||
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { getIDEViewMode } from "selectors/ideSelectors";
|
||||
import { getPropertyPaneWidth } from "selectors/propertyPaneSelectors";
|
||||
import history, { NavigationMethod } from "utils/history";
|
||||
import {
|
||||
builderURL,
|
||||
|
|
@ -20,11 +17,6 @@ import {
|
|||
} from "ee/RouteBuilder";
|
||||
import { getCurrentFocusInfo } from "selectors/focusHistorySelectors";
|
||||
import { getCurrentGitBranch } from "selectors/gitSyncSelectors";
|
||||
import {
|
||||
APP_SIDEBAR_WIDTH,
|
||||
DEFAULT_EXPLORER_PANE_WIDTH,
|
||||
SPLIT_SCREEN_RATIO,
|
||||
} from "constants/AppConstants";
|
||||
import { getIsAltFocusWidget, getWidgetSelectionBlock } from "selectors/ui";
|
||||
import { altFocusWidget, setWidgetSelectionBlock } from "actions/widgetActions";
|
||||
import { useJSAdd } from "ee/pages/Editor/IDE/EditorPane/JS/hooks";
|
||||
|
|
@ -36,7 +28,6 @@ import { closeJSActionTab } from "actions/jsActionActions";
|
|||
import { closeQueryActionTab } from "actions/pluginActionActions";
|
||||
import { getCurrentBasePageId } from "selectors/editorSelectors";
|
||||
import { getCurrentEntityInfo } from "../utils";
|
||||
import useWindowDimensions from "../../../utils/hooks/useWindowDimensions";
|
||||
|
||||
export const useCurrentAppState = () => {
|
||||
const [appState, setAppState] = useState(EditorState.EDITOR);
|
||||
|
|
@ -75,32 +66,6 @@ export const useCurrentEditorState = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const useEditorPaneWidth = (): string => {
|
||||
const [windowWidth] = useWindowDimensions();
|
||||
const [width, setWidth] = useState(windowWidth - APP_SIDEBAR_WIDTH + "px");
|
||||
const editorMode = useSelector(getIDEViewMode);
|
||||
const { segment } = useCurrentEditorState();
|
||||
const propertyPaneWidth = useSelector(getPropertyPaneWidth);
|
||||
useEffect(() => {
|
||||
if (editorMode === EditorViewMode.SplitScreen) {
|
||||
if (segment !== EditorEntityTab.UI) {
|
||||
// 1px is propertypane border width
|
||||
setWidth(windowWidth * SPLIT_SCREEN_RATIO + "px");
|
||||
} else {
|
||||
setWidth(DEFAULT_EXPLORER_PANE_WIDTH + "px");
|
||||
}
|
||||
} else {
|
||||
if (segment !== EditorEntityTab.UI) {
|
||||
setWidth(windowWidth - APP_SIDEBAR_WIDTH + "px");
|
||||
} else {
|
||||
setWidth(DEFAULT_EXPLORER_PANE_WIDTH + "px");
|
||||
}
|
||||
}
|
||||
}, [editorMode, segment, propertyPaneWidth, windowWidth]);
|
||||
|
||||
return width;
|
||||
};
|
||||
|
||||
export const useSegmentNavigation = (): {
|
||||
onSegmentChange: (value: string) => void;
|
||||
} => {
|
||||
|
|
|
|||
|
|
@ -1,61 +1,28 @@
|
|||
import React from "react";
|
||||
import { selectFeatureFlagCheck } from "ee/selectors/featureFlagsSelectors";
|
||||
import { AnimatedLayout, UnanimatedLayout } from "./Layout";
|
||||
import { useSelector } from "react-redux";
|
||||
import type { AppState } from "ee/reducers";
|
||||
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||
|
||||
import BottomBar from "components/BottomBar";
|
||||
import {
|
||||
combinedPreviewModeSelector,
|
||||
previewModeSelector,
|
||||
} from "selectors/editorSelectors";
|
||||
import EditorWrapperContainer from "../commons/EditorWrapperContainer";
|
||||
import Sidebar from "pages/Editor/IDE/Sidebar";
|
||||
import LeftPane from "./LeftPane";
|
||||
import MainPane from "./MainPane";
|
||||
import RightPane from "./RightPane";
|
||||
import classNames from "classnames";
|
||||
import { tailwindLayers } from "constants/Layers";
|
||||
import { protectedModeSelector } from "selectors/gitSyncSelectors";
|
||||
import ProtectedCallout from "./ProtectedCallout";
|
||||
const checkAnimatedIDEFlagValue = (state: AppState) => {
|
||||
return selectFeatureFlagCheck(
|
||||
state,
|
||||
FEATURE_FLAG.release_ide_animations_enabled,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* OldName: MainContainer
|
||||
*/
|
||||
function IDE() {
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const isCombinedPreviewMode = useSelector(combinedPreviewModeSelector);
|
||||
const isProtectedMode = useSelector(protectedModeSelector);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isProtectedMode && <ProtectedCallout />}
|
||||
<EditorWrapperContainer>
|
||||
<div
|
||||
className={classNames({
|
||||
[`transition-transform transform duration-400 flex h-full ${tailwindLayers.entityExplorer}`]:
|
||||
true,
|
||||
relative: !isCombinedPreviewMode,
|
||||
"-translate-x-full fixed": isCombinedPreviewMode,
|
||||
})}
|
||||
>
|
||||
<Sidebar />
|
||||
<LeftPane />
|
||||
</div>
|
||||
<MainPane id="app-body" />
|
||||
<div
|
||||
className={classNames({
|
||||
[`transition-transform transform duration-400 h-full ${tailwindLayers.propertyPane}`]:
|
||||
true,
|
||||
relative: !isCombinedPreviewMode,
|
||||
"translate-x-full fixed right-0": isCombinedPreviewMode,
|
||||
})}
|
||||
>
|
||||
<RightPane />
|
||||
</div>
|
||||
</EditorWrapperContainer>
|
||||
<BottomBar viewMode={isPreviewMode} />
|
||||
</>
|
||||
);
|
||||
const isAnimatedIDEEnabled = useSelector(checkAnimatedIDEFlagValue);
|
||||
if (isAnimatedIDEEnabled) {
|
||||
return <AnimatedLayout />;
|
||||
}
|
||||
return <UnanimatedLayout />;
|
||||
}
|
||||
|
||||
IDE.displayName = "AppsmithIDE";
|
||||
IDE.displayName = "AppIDE";
|
||||
|
||||
export default React.memo(IDE);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
RUN_GUTTER_ID,
|
||||
} from "./constants";
|
||||
import { thinScrollbar } from "constants/DefaultTheme";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
|
||||
export const CodeEditorWithGutterStyles = css`
|
||||
.${RUN_GUTTER_ID} {
|
||||
|
|
@ -31,7 +32,7 @@ export const CodeEditorWithGutterStyles = css`
|
|||
`;
|
||||
|
||||
export const FormWrapper = styled.div`
|
||||
height: ${({ theme }) => `calc(100vh - ${theme.smallHeaderHeight})`};
|
||||
height: calc(100vh - ${IDE_HEADER_HEIGHT}px);
|
||||
overflow: hidden;
|
||||
.${JS_OBJECT_HOTKEYS_CLASSNAME} {
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ import useInteractionAnalyticsEvent from "utils/hooks/useInteractionAnalyticsEve
|
|||
|
||||
import type { WidgetType } from "constants/WidgetConstants";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import { getIsCurrentWidgetRecentlyAdded } from "selectors/propertyPaneSelectors";
|
||||
import {
|
||||
getIsCurrentWidgetRecentlyAdded,
|
||||
getPropertyPaneWidth,
|
||||
} from "selectors/propertyPaneSelectors";
|
||||
|
||||
interface PropertyPaneTitleProps {
|
||||
title: string;
|
||||
|
|
@ -63,6 +66,7 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
|
|||
const isCurrentWidgetRecentlyAdded = useSelector(
|
||||
getIsCurrentWidgetRecentlyAdded,
|
||||
);
|
||||
const width = useSelector(getPropertyPaneWidth);
|
||||
|
||||
const { dispatchInteractionAnalyticsEvent, eventEmitterRef } =
|
||||
useInteractionAnalyticsEvent<HTMLDivElement>();
|
||||
|
|
@ -160,8 +164,9 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
|
|||
|
||||
return props.widgetId || props.isPanelTitle ? (
|
||||
<div
|
||||
className="flex items-center w-full px-4 py-3 space-x-1 fixed bg-white z-3"
|
||||
className="flex items-center px-4 py-3 space-x-1 fixed bg-white z-3"
|
||||
ref={eventEmitterRef}
|
||||
style={{ width: width + "px" }}
|
||||
>
|
||||
{/* BACK BUTTON */}
|
||||
{props.isPanelTitle && (
|
||||
|
|
|
|||
|
|
@ -7,6 +7,13 @@ import { useSelector } from "react-redux";
|
|||
import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors";
|
||||
import { EditorState } from "ee/entities/IDE/constants";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import styled from "styled-components";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
import { BOTTOM_BAR_HEIGHT } from "components/BottomBar/constants";
|
||||
|
||||
const Container = styled.div`
|
||||
height: calc(100vh - ${IDE_HEADER_HEIGHT} - ${BOTTOM_BAR_HEIGHT});
|
||||
`;
|
||||
|
||||
/**
|
||||
* WidgetEditorContainer
|
||||
|
|
@ -21,7 +28,7 @@ export const WidgetEditorContainer = (props: { children: ReactNode }) => {
|
|||
appState === EditorState.SETTINGS && isNavigationSelectedInSettings;
|
||||
return (
|
||||
<EditorContextProvider renderMode={RenderModes.CANVAS}>
|
||||
<div className="relative flex flex-row h-full w-full overflow-hidden">
|
||||
<Container className="relative flex flex-row h-full w-full overflow-hidden">
|
||||
<div
|
||||
className={classNames({
|
||||
"relative flex flex-col w-full overflow-hidden": true,
|
||||
|
|
@ -31,7 +38,7 @@ export const WidgetEditorContainer = (props: { children: ReactNode }) => {
|
|||
>
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</EditorContextProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { setPropertyPaneWidthAction } from "actions/propertyPaneActions";
|
||||
import React from "react";
|
||||
import PropertyPaneSidebar from "components/editorComponents/PropertyPaneSidebar";
|
||||
import React, { useCallback } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { getPropertyPaneWidth } from "selectors/propertyPaneSelectors";
|
||||
import { CreateNewQueryModal } from "pages/Editor/IDE/RightPane/components/CreateNewQueryModal";
|
||||
|
||||
/**
|
||||
|
|
@ -12,32 +9,9 @@ import { CreateNewQueryModal } from "pages/Editor/IDE/RightPane/components/Creat
|
|||
* It is used to handle the width of the property pane sidebar.
|
||||
*/
|
||||
function PropertyPaneWrapper() {
|
||||
const dispatch = useDispatch();
|
||||
const propertyPaneWidth = useSelector(getPropertyPaneWidth);
|
||||
|
||||
/**
|
||||
* on property pane sidebar drag end
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
const onRightSidebarDragEnd = useCallback(() => {
|
||||
dispatch(setPropertyPaneWidthAction(propertyPaneWidth));
|
||||
}, [propertyPaneWidth]);
|
||||
|
||||
/**
|
||||
* on property pane sidebar width change
|
||||
*/
|
||||
const onRightSidebarWidthChange = useCallback((newWidth) => {
|
||||
dispatch(setPropertyPaneWidthAction(newWidth));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PropertyPaneSidebar
|
||||
onDragEnd={onRightSidebarDragEnd}
|
||||
onWidthChange={onRightSidebarWidthChange}
|
||||
width={propertyPaneWidth}
|
||||
/>
|
||||
<PropertyPaneSidebar />
|
||||
<CreateNewQueryModal />
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import styled from "styled-components";
|
||||
import { Profile } from "pages/common/ProfileImage";
|
||||
import { getTypographyByKey } from "@appsmith/ads-old";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
|
||||
export const HeaderWrapper = styled.div`
|
||||
width: 100%;
|
||||
|
|
@ -10,7 +11,7 @@ export const HeaderWrapper = styled.div`
|
|||
flex-direction: row;
|
||||
box-shadow: none;
|
||||
border-bottom: 1px solid var(--ads-v2-color-border);
|
||||
height: ${(props) => props.theme.smallHeaderHeight};
|
||||
height: ${IDE_HEADER_HEIGHT}px;
|
||||
& .editable-application-name {
|
||||
${getTypographyByKey("h4")}
|
||||
color: ${(props) => props.theme.colors.header.appName};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { APP_SETTINGS_PANE_WIDTH } from "constants/AppConstants";
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import PaneHeader from "../IDE/LeftPane/PaneHeader";
|
||||
|
|
@ -10,7 +9,7 @@ type EditorSettingsPaneContainerProps = React.PropsWithChildren<{
|
|||
const SettingsPageWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: ${APP_SETTINGS_PANE_WIDTH}px;
|
||||
width: 100%;
|
||||
|
||||
&:nth-child(2) {
|
||||
height: 100%;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import classNames from "classnames";
|
|||
import { useSelector } from "react-redux";
|
||||
import { combinedPreviewModeSelector } from "../../../selectors/editorSelectors";
|
||||
import { protectedModeSelector } from "selectors/gitSyncSelectors";
|
||||
import { IDE_HEADER_HEIGHT } from "../../../IDE";
|
||||
import { BOTTOM_BAR_HEIGHT } from "../../../components/BottomBar/constants";
|
||||
import { PROTECTED_CALLOUT_HEIGHT } from "../IDE/ProtectedCallout";
|
||||
|
||||
interface EditorWrapperContainerProps {
|
||||
children: React.ReactNode;
|
||||
|
|
@ -14,9 +17,9 @@ const Wrapper = styled.div<{
|
|||
}>`
|
||||
display: flex;
|
||||
height: calc(
|
||||
100vh - ${(props) => props.theme.smallHeaderHeight} -
|
||||
${(props) => props.theme.bottomBarHeight} -
|
||||
${(props) => (props.isProtectedMode ? "70px" : "0px")}
|
||||
100vh - ${IDE_HEADER_HEIGHT}px - ${BOTTOM_BAR_HEIGHT}px -
|
||||
${(props) =>
|
||||
props.isProtectedMode ? PROTECTED_CALLOUT_HEIGHT + "px" : "0px"}
|
||||
);
|
||||
background-color: ${(props) => props.theme.appBackground};
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ import styled from "styled-components";
|
|||
import { snipingModeSelector } from "selectors/editorSelectors";
|
||||
import { retryPromise } from "utils/AppsmithUtils";
|
||||
import { useSelector } from "react-redux";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
|
||||
const BindingBanner = styled.div`
|
||||
position: fixed;
|
||||
width: 199px;
|
||||
height: 36px;
|
||||
left: 50%;
|
||||
top: ${(props) => props.theme.smallHeaderHeight};
|
||||
top: ${IDE_HEADER_HEIGHT}px;
|
||||
transform: translate(-50%, 0);
|
||||
text-align: center;
|
||||
background: var(--ads-v2-color-fg-information);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { Colors } from "constants/Colors";
|
|||
import ConflictInfo from "../components/ConflictInfo";
|
||||
import { getCurrentAppGitMetaData } from "ee/selectors/applicationSelectors";
|
||||
import { Button } from "@appsmith/ads";
|
||||
import { BOTTOM_BAR_HEIGHT } from "../../../../components/BottomBar/constants";
|
||||
|
||||
const StyledGitErrorPopup = styled.div`
|
||||
& {
|
||||
|
|
@ -31,7 +32,7 @@ const StyledGitErrorPopup = styled.div`
|
|||
.${Classes.OVERLAY_CONTENT} {
|
||||
overflow: hidden;
|
||||
bottom: ${(props) =>
|
||||
`calc(${props.theme.bottomBarHeight} + ${props.theme.spaces[3]}px)`};
|
||||
`calc(${BOTTOM_BAR_HEIGHT}px + ${props.theme.spaces[3]}px)`};
|
||||
left: ${(props) => props.theme.spaces[3]}px;
|
||||
background-color: ${Colors.WHITE};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import { PartialExportModal } from "components/editorComponents/PartialImportExp
|
|||
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 "IDE";
|
||||
|
||||
interface EditorProps {
|
||||
currentApplicationId?: string;
|
||||
|
|
@ -175,7 +176,7 @@ class Editor extends Component<Props> {
|
|||
if (!this.props.isEditorInitialized || this.props.loadingGuidedTour) {
|
||||
return (
|
||||
<CenteredWrapper
|
||||
style={{ height: `calc(100vh - ${theme.smallHeaderHeight})` }}
|
||||
style={{ height: `calc(100vh - ${IDE_HEADER_HEIGHT}px)` }}
|
||||
>
|
||||
<Spinner size="lg" />
|
||||
</CenteredWrapper>
|
||||
|
|
|
|||
|
|
@ -10631,6 +10631,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/dom-view-transitions@npm:^1.0.5":
|
||||
version: 1.0.5
|
||||
resolution: "@types/dom-view-transitions@npm:1.0.5"
|
||||
checksum: 4190915a3d4c63d4c590d5e64d14ca1d1140496a75adb5af64b0ef13e075cc7676bff926f5c5c60305c4f6d46965a196c119a7960cbe0ff40e95e17e82334c22
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/dom4@npm:^2.0.1":
|
||||
version: 2.0.2
|
||||
resolution: "@types/dom4@npm:2.0.2"
|
||||
|
|
@ -13214,6 +13221,7 @@ __metadata:
|
|||
"@types/d3-geo": ^3.1.0
|
||||
"@types/deep-diff": ^1.0.0
|
||||
"@types/dom-mediacapture-record": ^1.0.11
|
||||
"@types/dom-view-transitions": ^1.0.5
|
||||
"@types/downloadjs": ^1.4.2
|
||||
"@types/google.maps": ^3.51.0
|
||||
"@types/jest": ^27.4.1
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user