PromucFlow_constructor/app/client/src/pages/Editor/MainContainer.test.tsx

1009 lines
27 KiB
TypeScript
Raw Normal View History

import React from "react";
import {
buildChildren,
widgetCanvasFactory,
} from "test/factories/WidgetFactoryUtils";
import { act, render, fireEvent } from "test/testUtils";
import GlobalHotKeys from "./GlobalHotKeys";
import { MemoryRouter } from "react-router-dom";
import * as utilities from "selectors/editorSelectors";
import store from "store";
import { sagasToRunForTests } from "test/sagas";
import { all } from "@redux-saga/core/effects";
import {
MockApplication,
mockGetCanvasWidgetDsl,
syntheticTestMouseEvent,
} from "test/testCommon";
import lodash from "lodash";
import { getAbsolutePixels } from "utils/helpers";
import { UpdatedMainContainer } from "test/testMockedWidgets";
import { AppState } from "reducers";
feat: Reflow and Resize while Dragging and Resizing widgets. (#9054) * resize n reflow rough cut * removing warnings * relatively stable changes * minor bug fix * reflow relative collision * working dp cut * fix for reflow of widgets closer next to each other * disabling scroll * Drag with reflow * reflow fix * overlap and retracing fix * On Drop updates. * bug when no displacement but resize update. * temp fix for new widget addition. * reflow bug fixes * new widget addition bug. * stop reflow on leave. * fix corner case overlap * update bottom row when reflowed widgets go beyond bottom boundary. * capture mouse positions on enter * enable container jumps with faster mouse movements. * reflow only for snap changes. * restructured reflow Algorithm * collision check and bug fixes * undo redo fix for new widget drop * resizable fix snapRows fix * directional stability * self collision fix * first round of perf fixes * update bottom row while resizing and resize-reflowing * performance fix and overlapping fix * Remove eslint warning * remove eslint warning * eslint warning * can reflowed Drop Indication Stability * container jumps and force direction on entering canvas * fixing scroll on resize jitters. * reflow when jumping into container. * reflow ux fixes while leaving container * resizing fixes. * fixes for edge move. * restrict container jumps into reflowed containers. * container jump direction reflow * checkbox dimensions fix. * Excess bottom rows not lost post dragging or resizing widgets. * fixing the after drop css glitch. * double first move trigger bug fix. * stop reflow only if reflowing * stabilize container exit directions * using acceleration and speed instead of movement covered to restrict reflow. * fixing modal drops. * remove warnings. * reflow resize styles * moving acceleration and movement logic to a monitoring effect. * adding beta flag for reflow. * fixing jest tests * Adding analytics to beta flag toggle. * Adding placeholder for reflow beta screens. * fixing initial load's screen * few more crashes. * force close onboarding for the session. * fixing bugs in reset canvas. * Beta flag bug fixes. * fixing bugs. * restrict reflow screens during onboarding. * disabling reflow screens in tests. * code review comments. * fixing store based specs. * fixing cypress failures. * fixing specs. * code cleanup * reverting yarn lock changes * removing onboarding screens. * more cleanup and function descriptors * keeping reflow under the hood. Co-authored-by: rahulramesha <rahul@appsmith.com> Co-authored-by: Arpit Mohan <arpit@appsmith.com>
2022-01-13 13:21:57 +00:00
import { generateReactKey } from "utils/generators";
const renderNestedComponent = () => {
const initialState = (store.getState() as unknown) as Partial<AppState>;
const canvasId = "canvas-id";
const containerId = "container-id";
const children: any = buildChildren([
{
type: "INPUT_WIDGET_V2",
dragDisabled: true,
leftColumn: 0,
topRow: 1,
parentId: canvasId,
rightColumn: 5,
bottomRow: 2,
text: "DRAG DISABLED INPUT",
},
{
type: "TEXT_WIDGET",
leftColumn: 0,
parentId: canvasId,
rightColumn: 5,
bottomRow: 3,
topRow: 2,
text: "LABEL",
widgetId: "text-widget",
},
]);
const canvasWidgetChildren: any = buildChildren([
{
type: "CANVAS_WIDGET",
parentId: containerId,
widgetId: canvasId,
children,
},
]);
const containerWidgetChildren: any = buildChildren([
{
type: "CONTAINER_WIDGET",
children: canvasWidgetChildren,
parentId: "0",
widgetId: containerId,
},
]);
const dsl: any = widgetCanvasFactory.build({
children: containerWidgetChildren,
});
return render(
<MemoryRouter
initialEntries={["/app/applicationSlug/pageSlug-page_id/edit"]}
>
<MockApplication>
<GlobalHotKeys>
<UpdatedMainContainer dsl={dsl} />
</GlobalHotKeys>
</MockApplication>
</MemoryRouter>,
{ initialState, sagasToRun: sagasToRunForTests },
);
};
describe("Drag and Drop widgets into Main container", () => {
const mockGetIsFetchingPage = jest.spyOn(utilities, "getIsFetchingPage");
const spyGetCanvasWidgetDsl = jest.spyOn(utilities, "getCanvasWidgetDsl");
feat: adding slug names in urls (#10957) * Init commit clean urls * Changes to builder route * Refactored URLs * Remove default params from url builder functions. * Fixed more urls * Changed selector name * Minor url correction * Type fixes * Jest fixes * Fixed routing for old published apps * Fixed url slug replace * page-1 -> page1 as default page slug name * Remove application id from init editor calls * Use default page slug * Added comments and placeholder values for slug names * variable rename * Removed redirection and added back the old routes * Prevent page slug name recompute * Fixed home page load in view mode * Added null checks * Fixed jest test * Fixed jest test * Update URL slugs when app/page name changes * Added unit tests and updates types * Removed unused code * * Removed duplication fetch page call. * Fixes #11354 * Fixed sign up flow * Refactored initializeEditorSaga * Fixed warnings * Fixed integrations screen URL bugs * Cypress fixes * Fixed slug names in copy/move operations and pages screen * Minor refactor * Fixed page highlight bug in published apps * Added new url factory and middleware to store url params * Changed store to default export and fix unit tests * Fixed slugs unit test * Minor fixes * Fixes #11379 * Fixed set as home page feature * Updated types * app id adjustments for cypress * Fixed bad merge * Refactored routes to functional component * * Fixed EE active entity highlight. * Remove unused code in editor router. * jest fix * Mock history to prevent security errors * constant rename * Removed console logs * Fixed page id regex * Do not check for /pages in url * Fixed missing pageId on quick edit/deploy clicks * Missed files from previous commit * Fixed warnings * Fixed jest test * New api integration * feat: Add applicationVersion property to Application (#11626) Added a new property to Application object - applicationVersion. This property can be used to identity when there is a breaking change and can not be solved with migration. FE will use this property to detect such conditions. Another API is added to migrate the applicationVersion to latest version when user migrates the breaking changes. * Added manual upgrade modal. * Test fix * Fixed jest test * function rename * Fix deploy error * Added null check * Changes to persist URL search params when redirecting * Added updates tooltip * More unit test cases * Fixed git url redirection * Fix warning * Fixed evaluation on upgrade * Fixed warnings * File rename * Added cypress for clean urls * Fixed import/export/fork cypress * Cypress api server fixes * Fixed mongo spec * Fixed replay spec * Fixed comments spec * More cypress fixes * Fixed tooltip in update btn * Text size changes * Minor fixes * Jest test fix * Fixed type error * Fixed warnings * Fixed todo comments * Moved description to constants file * Fixed cypress CI run crash * Fixes git cypress failures * Import/Export cypress test fixes * Import export fork cypress fixes * Explorer test fix * Switch branch test fix * Added applicationVersion in export app json * Calls plugin forms in parallel * Fixed warnings * Fixed warning * Import export CI fixes * Reverts previous changes * Fixes import export * Fixed import export cypress URL verification * Pass applicationVersion when duplicating application * Cypress fix * Dummy commit Co-authored-by: Nayan <nayan@appsmith.com>
2022-03-25 10:43:26 +00:00
const pushState = jest.spyOn(window.history, "pushState");
pushState.mockImplementation((state: any, title: any, url: any) => {
window.document.title = title;
window.location.pathname = url;
});
// These need to be at the top to avoid imports not being mocked. ideally should be in setup.ts but will override for all other tests
beforeAll(() => {
const mockGenerator = function*() {
yield all([]);
};
const debounceMocked = jest.spyOn(lodash, "debounce");
debounceMocked.mockImplementation((fn: any) => fn);
// top avoid the first middleware run which wud initiate all sagas.
jest.mock("sagas", () => ({
rootSaga: mockGenerator,
}));
// only the deafault exports are mocked to avoid overriding utilities exported out of them. defaults are marked to avoid worker initiation and page api calls in tests.
jest.mock("sagas/EvaluationsSaga", () => ({
...jest.requireActual("sagas/EvaluationsSaga"),
default: mockGenerator,
}));
jest.mock("sagas/PageSagas", () => ({
...jest.requireActual("sagas/PageSagas"),
default: mockGenerator,
}));
});
it("Drag to move widgets", () => {
const children: any = buildChildren([
{
type: "TABS_WIDGET",
topRow: 5,
bottomRow: 5,
leftColumn: 5,
rightColumn: 5,
},
]);
const dsl: any = widgetCanvasFactory.build({
children,
});
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = render(
<MemoryRouter
initialEntries={["/app/applicationSlug/pageSlug-page_id/edit"]}
>
<MockApplication>
<GlobalHotKeys>
<UpdatedMainContainer dsl={dsl} />
</GlobalHotKeys>
</MockApplication>
</MemoryRouter>,
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
);
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(1);
const tabsWidget: any = component.container.querySelector(
".t--draggable-tabswidget",
);
const tab: any = component.container.querySelector(".t--widget-tabswidget");
const initPositions = {
left: tab.style.left,
top: tab.style.top,
};
act(() => {
fireEvent.mouseOver(tabsWidget);
});
act(() => {
fireEvent.dragStart(tabsWidget);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 0,
offsetY: 0,
},
),
);
});
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: -50,
offsetY: -50,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
),
);
});
const movedTab: any = component.container.querySelector(
".t--widget-tabswidget",
);
const finalPositions = {
left: movedTab.style.left,
top: movedTab.style.top,
};
expect(finalPositions.left).not.toEqual(initPositions.left);
expect(finalPositions.top).not.toEqual(initPositions.top);
});
it("When widgets are moved out of main container bounds move them back to previous position", () => {
const children: any = buildChildren([
{
type: "TABS_WIDGET",
topRow: 5,
bottomRow: 5,
leftColumn: 5,
rightColumn: 5,
},
]);
const dsl: any = widgetCanvasFactory.build({
children,
});
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = render(
<MemoryRouter
initialEntries={["/app/applicationSlug/pageSlug-page_id/edit"]}
>
<MockApplication>
<GlobalHotKeys>
<UpdatedMainContainer dsl={dsl} />
</GlobalHotKeys>
</MockApplication>
</MemoryRouter>,
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
);
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(1);
const tabsWidget: any = component.container.querySelector(
".t--draggable-tabswidget",
);
const tab: any = component.container.querySelector(".t--widget-tabswidget");
const initPositions = {
left: tab.style.left,
top: tab.style.top,
};
act(() => {
fireEvent.mouseOver(tabsWidget);
});
act(() => {
fireEvent.dragStart(tabsWidget);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 0,
offsetY: 0,
},
),
);
});
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: -500,
offsetY: -500,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
),
);
});
const movedTab: any = component.container.querySelector(
".t--widget-tabswidget",
);
const finalPositions = {
left: movedTab.style.left,
top: movedTab.style.top,
};
expect(finalPositions.left).toEqual(initPositions.left);
expect(finalPositions.top).toEqual(initPositions.top);
});
it("When widgets are colliding with other widgets move them back to previous position", () => {
const children: any = buildChildren([
{
type: "TABS_WIDGET",
topRow: 5,
bottomRow: 15,
leftColumn: 5,
rightColumn: 15,
},
{
type: "TABLE_WIDGET",
topRow: 15,
bottomRow: 25,
leftColumn: 5,
rightColumn: 15,
},
]);
const dsl: any = widgetCanvasFactory.build({
children,
});
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = render(
<MemoryRouter
initialEntries={["/app/applicationSlug/pageSlug-page_id/edit"]}
>
<MockApplication>
<GlobalHotKeys>
<UpdatedMainContainer dsl={dsl} />
</GlobalHotKeys>
</MockApplication>
</MemoryRouter>,
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
);
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(2);
const tabsWidget: any = component.container.querySelector(
".t--draggable-tabswidget",
);
const tab: any = component.container.querySelector(".t--widget-tabswidget");
const initPositions = {
left: tab.style.left,
top: tab.style.top,
};
act(() => {
fireEvent.mouseOver(tabsWidget);
});
act(() => {
fireEvent.dragStart(tabsWidget);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 0,
offsetY: 0,
},
),
);
});
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 0,
offsetY: 50,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
),
);
});
const movedTab: any = component.container.querySelector(
".t--widget-tabswidget",
);
const finalPositions = {
left: movedTab.style.left,
top: movedTab.style.top,
};
expect(finalPositions.left).toEqual(initPositions.left);
expect(finalPositions.top).toEqual(initPositions.top);
});
it("When widgets are out of bottom most bounds of parent canvas, canvas has to expand", () => {
const children: any = buildChildren([
{
type: "TABS_WIDGET",
topRow: 5,
bottomRow: 15,
leftColumn: 5,
rightColumn: 15,
},
{
type: "TABLE_WIDGET",
topRow: 15,
bottomRow: 25,
leftColumn: 5,
rightColumn: 15,
},
]);
const dsl: any = widgetCanvasFactory.build({
children,
});
dsl.bottomRow = 250;
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = render(
<MemoryRouter
initialEntries={["/app/applicationSlug/pageSlug-page_id/edit"]}
>
<MockApplication>
<GlobalHotKeys>
<UpdatedMainContainer dsl={dsl} />
</GlobalHotKeys>
</MockApplication>
</MemoryRouter>,
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
);
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(2);
const tabsWidget: any = component.container.querySelector(
".t--draggable-tablewidget",
);
act(() => {
fireEvent.mouseOver(tabsWidget);
});
act(() => {
fireEvent.dragStart(tabsWidget);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
const dropTarget: any = component.container.getElementsByClassName(
"t--drop-target",
)[0];
let initialLength = dropTarget.style.height;
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 0,
offsetY: 0,
},
),
);
});
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 0,
offsetY: 300,
// min height - (component height + bottom row)
},
),
);
});
let updatedDropTarget: any = component.container.getElementsByClassName(
"t--drop-target",
)[0];
let updatedLength = updatedDropTarget.style.height;
expect(initialLength).not.toEqual(updatedLength);
initialLength = updatedLength;
const amountMovedY = 300;
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 0,
offsetY: 300 + amountMovedY,
},
),
);
});
updatedDropTarget = component.container.getElementsByClassName(
"t--drop-target",
)[0];
updatedLength = updatedDropTarget.style.height;
expect(getAbsolutePixels(initialLength) + amountMovedY).toEqual(
getAbsolutePixels(updatedLength),
);
});
it("Drag and Drop widget into an empty canvas", () => {
const children: any = buildChildren([]);
const dsl: any = widgetCanvasFactory.build({
children,
});
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = render(
<MemoryRouter
initialEntries={["/app/applicationSlug/pageSlug-page_id/edit"]}
>
<MockApplication>
<GlobalHotKeys>
<UpdatedMainContainer dsl={dsl} />
</GlobalHotKeys>
</MockApplication>
</MemoryRouter>,
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
);
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
// empty canvas
expect(canvasWidgets.length).toBe(0);
const allAddEntityButtons: any = component.container.querySelectorAll(
".t--entity-add-btn",
);
const widgetAddButton = allAddEntityButtons[1];
act(() => {
fireEvent.click(widgetAddButton);
});
const containerButton: any = component.queryAllByText("Container");
act(() => {
fireEvent.dragStart(containerButton[0]);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 200,
offsetY: 200,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 200,
offsetY: 200,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 200,
offsetY: 200,
},
),
);
});
const newlyAddedCanvas = component.container.querySelectorAll(
"div[type='CONTAINER_WIDGET']",
);
expect(newlyAddedCanvas.length).toBe(1);
});
it("Disallow drag if widget not focused", () => {
const initialState = (store.getState() as unknown) as Partial<AppState>;
feat: Reflow and Resize while Dragging and Resizing widgets. (#9054) * resize n reflow rough cut * removing warnings * relatively stable changes * minor bug fix * reflow relative collision * working dp cut * fix for reflow of widgets closer next to each other * disabling scroll * Drag with reflow * reflow fix * overlap and retracing fix * On Drop updates. * bug when no displacement but resize update. * temp fix for new widget addition. * reflow bug fixes * new widget addition bug. * stop reflow on leave. * fix corner case overlap * update bottom row when reflowed widgets go beyond bottom boundary. * capture mouse positions on enter * enable container jumps with faster mouse movements. * reflow only for snap changes. * restructured reflow Algorithm * collision check and bug fixes * undo redo fix for new widget drop * resizable fix snapRows fix * directional stability * self collision fix * first round of perf fixes * update bottom row while resizing and resize-reflowing * performance fix and overlapping fix * Remove eslint warning * remove eslint warning * eslint warning * can reflowed Drop Indication Stability * container jumps and force direction on entering canvas * fixing scroll on resize jitters. * reflow when jumping into container. * reflow ux fixes while leaving container * resizing fixes. * fixes for edge move. * restrict container jumps into reflowed containers. * container jump direction reflow * checkbox dimensions fix. * Excess bottom rows not lost post dragging or resizing widgets. * fixing the after drop css glitch. * double first move trigger bug fix. * stop reflow only if reflowing * stabilize container exit directions * using acceleration and speed instead of movement covered to restrict reflow. * fixing modal drops. * remove warnings. * reflow resize styles * moving acceleration and movement logic to a monitoring effect. * adding beta flag for reflow. * fixing jest tests * Adding analytics to beta flag toggle. * Adding placeholder for reflow beta screens. * fixing initial load's screen * few more crashes. * force close onboarding for the session. * fixing bugs in reset canvas. * Beta flag bug fixes. * fixing bugs. * restrict reflow screens during onboarding. * disabling reflow screens in tests. * code review comments. * fixing store based specs. * fixing cypress failures. * fixing specs. * code cleanup * reverting yarn lock changes * removing onboarding screens. * more cleanup and function descriptors * keeping reflow under the hood. Co-authored-by: rahulramesha <rahul@appsmith.com> Co-authored-by: Arpit Mohan <arpit@appsmith.com>
2022-01-13 13:21:57 +00:00
const containerId = generateReactKey();
const canvasId = generateReactKey();
feat: Reflow and Resize while Dragging and Resizing widgets. (#9054) * resize n reflow rough cut * removing warnings * relatively stable changes * minor bug fix * reflow relative collision * working dp cut * fix for reflow of widgets closer next to each other * disabling scroll * Drag with reflow * reflow fix * overlap and retracing fix * On Drop updates. * bug when no displacement but resize update. * temp fix for new widget addition. * reflow bug fixes * new widget addition bug. * stop reflow on leave. * fix corner case overlap * update bottom row when reflowed widgets go beyond bottom boundary. * capture mouse positions on enter * enable container jumps with faster mouse movements. * reflow only for snap changes. * restructured reflow Algorithm * collision check and bug fixes * undo redo fix for new widget drop * resizable fix snapRows fix * directional stability * self collision fix * first round of perf fixes * update bottom row while resizing and resize-reflowing * performance fix and overlapping fix * Remove eslint warning * remove eslint warning * eslint warning * can reflowed Drop Indication Stability * container jumps and force direction on entering canvas * fixing scroll on resize jitters. * reflow when jumping into container. * reflow ux fixes while leaving container * resizing fixes. * fixes for edge move. * restrict container jumps into reflowed containers. * container jump direction reflow * checkbox dimensions fix. * Excess bottom rows not lost post dragging or resizing widgets. * fixing the after drop css glitch. * double first move trigger bug fix. * stop reflow only if reflowing * stabilize container exit directions * using acceleration and speed instead of movement covered to restrict reflow. * fixing modal drops. * remove warnings. * reflow resize styles * moving acceleration and movement logic to a monitoring effect. * adding beta flag for reflow. * fixing jest tests * Adding analytics to beta flag toggle. * Adding placeholder for reflow beta screens. * fixing initial load's screen * few more crashes. * force close onboarding for the session. * fixing bugs in reset canvas. * Beta flag bug fixes. * fixing bugs. * restrict reflow screens during onboarding. * disabling reflow screens in tests. * code review comments. * fixing store based specs. * fixing cypress failures. * fixing specs. * code cleanup * reverting yarn lock changes * removing onboarding screens. * more cleanup and function descriptors * keeping reflow under the hood. Co-authored-by: rahulramesha <rahul@appsmith.com> Co-authored-by: Arpit Mohan <arpit@appsmith.com>
2022-01-13 13:21:57 +00:00
const canvasWidget = buildChildren([
{
type: "CANVAS_WIDGET",
parentId: containerId,
children: [],
widgetId: canvasId,
dropDisabled: true,
},
]);
const containerChildren: any = buildChildren([
{
type: "CONTAINER_WIDGET",
feat: Reflow and Resize while Dragging and Resizing widgets. (#9054) * resize n reflow rough cut * removing warnings * relatively stable changes * minor bug fix * reflow relative collision * working dp cut * fix for reflow of widgets closer next to each other * disabling scroll * Drag with reflow * reflow fix * overlap and retracing fix * On Drop updates. * bug when no displacement but resize update. * temp fix for new widget addition. * reflow bug fixes * new widget addition bug. * stop reflow on leave. * fix corner case overlap * update bottom row when reflowed widgets go beyond bottom boundary. * capture mouse positions on enter * enable container jumps with faster mouse movements. * reflow only for snap changes. * restructured reflow Algorithm * collision check and bug fixes * undo redo fix for new widget drop * resizable fix snapRows fix * directional stability * self collision fix * first round of perf fixes * update bottom row while resizing and resize-reflowing * performance fix and overlapping fix * Remove eslint warning * remove eslint warning * eslint warning * can reflowed Drop Indication Stability * container jumps and force direction on entering canvas * fixing scroll on resize jitters. * reflow when jumping into container. * reflow ux fixes while leaving container * resizing fixes. * fixes for edge move. * restrict container jumps into reflowed containers. * container jump direction reflow * checkbox dimensions fix. * Excess bottom rows not lost post dragging or resizing widgets. * fixing the after drop css glitch. * double first move trigger bug fix. * stop reflow only if reflowing * stabilize container exit directions * using acceleration and speed instead of movement covered to restrict reflow. * fixing modal drops. * remove warnings. * reflow resize styles * moving acceleration and movement logic to a monitoring effect. * adding beta flag for reflow. * fixing jest tests * Adding analytics to beta flag toggle. * Adding placeholder for reflow beta screens. * fixing initial load's screen * few more crashes. * force close onboarding for the session. * fixing bugs in reset canvas. * Beta flag bug fixes. * fixing bugs. * restrict reflow screens during onboarding. * disabling reflow screens in tests. * code review comments. * fixing store based specs. * fixing cypress failures. * fixing specs. * code cleanup * reverting yarn lock changes * removing onboarding screens. * more cleanup and function descriptors * keeping reflow under the hood. Co-authored-by: rahulramesha <rahul@appsmith.com> Co-authored-by: Arpit Mohan <arpit@appsmith.com>
2022-01-13 13:21:57 +00:00
children: canvasWidget,
widgetId: containerId,
parentId: "0",
},
]);
const dsl: any = widgetCanvasFactory.build({
feat: Reflow and Resize while Dragging and Resizing widgets. (#9054) * resize n reflow rough cut * removing warnings * relatively stable changes * minor bug fix * reflow relative collision * working dp cut * fix for reflow of widgets closer next to each other * disabling scroll * Drag with reflow * reflow fix * overlap and retracing fix * On Drop updates. * bug when no displacement but resize update. * temp fix for new widget addition. * reflow bug fixes * new widget addition bug. * stop reflow on leave. * fix corner case overlap * update bottom row when reflowed widgets go beyond bottom boundary. * capture mouse positions on enter * enable container jumps with faster mouse movements. * reflow only for snap changes. * restructured reflow Algorithm * collision check and bug fixes * undo redo fix for new widget drop * resizable fix snapRows fix * directional stability * self collision fix * first round of perf fixes * update bottom row while resizing and resize-reflowing * performance fix and overlapping fix * Remove eslint warning * remove eslint warning * eslint warning * can reflowed Drop Indication Stability * container jumps and force direction on entering canvas * fixing scroll on resize jitters. * reflow when jumping into container. * reflow ux fixes while leaving container * resizing fixes. * fixes for edge move. * restrict container jumps into reflowed containers. * container jump direction reflow * checkbox dimensions fix. * Excess bottom rows not lost post dragging or resizing widgets. * fixing the after drop css glitch. * double first move trigger bug fix. * stop reflow only if reflowing * stabilize container exit directions * using acceleration and speed instead of movement covered to restrict reflow. * fixing modal drops. * remove warnings. * reflow resize styles * moving acceleration and movement logic to a monitoring effect. * adding beta flag for reflow. * fixing jest tests * Adding analytics to beta flag toggle. * Adding placeholder for reflow beta screens. * fixing initial load's screen * few more crashes. * force close onboarding for the session. * fixing bugs in reset canvas. * Beta flag bug fixes. * fixing bugs. * restrict reflow screens during onboarding. * disabling reflow screens in tests. * code review comments. * fixing store based specs. * fixing cypress failures. * fixing specs. * code cleanup * reverting yarn lock changes * removing onboarding screens. * more cleanup and function descriptors * keeping reflow under the hood. Co-authored-by: rahulramesha <rahul@appsmith.com> Co-authored-by: Arpit Mohan <arpit@appsmith.com>
2022-01-13 13:21:57 +00:00
children: containerChildren,
});
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = render(
<MemoryRouter
initialEntries={["/app/applicationSlug/pageSlug-page_id/edit"]}
>
<MockApplication>
<GlobalHotKeys>
<UpdatedMainContainer dsl={dsl} />
</GlobalHotKeys>
</MockApplication>
</MemoryRouter>,
{ initialState, sagasToRun: sagasToRunForTests },
);
const widget: any = component.container.querySelector(
".t--widget-containerwidget",
);
const draggableWidget: any = component.container.querySelector(
".t--draggable-containerwidget",
);
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(1);
const initWidgetPosition = {
left: widget.style.left,
top: widget.style.top,
};
act(() => {
fireEvent.dragStart(draggableWidget);
});
let mainCanvas: any = component.queryByTestId("div-dragarena-0");
expect(mainCanvas).toBeNull();
// Focus on widget and drag
act(() => {
fireEvent.mouseOver(draggableWidget);
});
act(() => {
fireEvent.dragStart(draggableWidget);
});
mainCanvas = component.queryByTestId("div-dragarena-0");
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
feat: property pane docking (#7361) * add tailwindcss * docked property pane * uncomment a line * make entity explorer as drawer on unpin * remove unused imports * add pin state in reducer * add menu icon in header * fix widget sidebar * fix widgets sidebar * style property pane * update property pane css * update icons in property pane * update property pane header styles * update spacing * fix few ui issues * wip: preview mode * wip:preview mode * remove unused import * comments sidebar in app and edit mode * fix order of import * use selected state for property pane * update scrollbar style * add classes to sidebar and property pane * make widgets editor fluid * make widgets editor fluid and refactor logic * resize the widgets editor if explorer is pinned * add shortcut for preview mode * fix link for tabs in edit mode * zoom in/zoom out for 0.75 * fix chart widget + table widget crashing * allow zooming of canvas * fix weird canvas draw issue + update container for handling zoom * add actions for is panning * allow panning with grab cursor * reset panning + zooming when entering preview mode * add grabbing cursor when grabbing * only prevent default when space key is pressed * dont allow zoom in preview mode * remove unused imports * fix dont allow zoom in preview mode * fix ux of panning on space hit * make fluid as the default app layout * chart spec * fix dropdown_on change spec * fix add widget table and bind spec * remove draggable property pane spec * fix container spec * fix form widget spec * fix jest test * fix the function typo * remove clicking of close button for property pane in cypress tests * remove property pane actions test * fix drag and drop test failing * add cypress selector id to back button in property pane * fix toggle js spec * fix merge conflicts from new design system * editor header * fix product updates styles + widget card * remove all unused imports * fix dynamic layout spec * fix entity explorer tab rename test failing * fix table spec * fix bind tabletextpagination spec * fix js object spec * fix entity explorer rename issue * fix cypress test * fix cypress command wrong commit * fix tab spec * fix property pane copy tests * add zoom header * zoom levels * make property pane sidebar resizable * add multi select property pane * fix widget search bug * update property pane width in state on drag end * fix viewer header * fix editor header * update editor header + remove zooming * update small style * dont allow closing of explorer when resizing * fix jest test * fix dropdown widget jest test * preview test case wip * add entity explorer pinning tests + preview mode tests * add tooltip in layout control + add padding bottom in property pane view * incorporate aakash feedbacks * fix preview mode margin issue * remove panning code * fix cypress failing test * uncomment jest test * remove redundant code * fix maincontainer test * incorporate review feedbacks * incorporate aakash feedbacks * review feedbacks * incorporate review feedbacks * incorporate qa feedbacks * fix dynamic layout spec * updated test based on latest change * dsl updated * Updated dsl * Updated dsl * resize deselects widget issue. * fix canvas height issue * fix typo * incorporate qa feedbacks * incorporate qa feedbacks * incorporate qa feedbacks * update color for setting control for widget name * fix onboarding styles conflicts * Updated tests * fix application overflow issue * updated test method Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local> Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com> Co-authored-by: Apple <nandan@thinkify.io>
2021-11-23 08:01:46 +00:00
offsetX: 100,
offsetY: 100,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
),
);
});
const movedWidget: any = component.container.querySelector(
".t--widget-containerwidget",
);
const finalWidgetPosition = {
left: movedWidget.style.left,
top: movedWidget.style.top,
};
expect(finalWidgetPosition).not.toStrictEqual(initWidgetPosition);
});
afterAll(() => jest.resetModules());
});
describe("Drag in a nested container", () => {
const mockGetIsFetchingPage = jest.spyOn(utilities, "getIsFetchingPage");
const spyGetCanvasWidgetDsl = jest.spyOn(utilities, "getCanvasWidgetDsl");
// These need to be at the top to avoid imports not being mocked. ideally should be in setup.ts but will override for all other tests
beforeAll(() => {
const mockGenerator = function*() {
yield all([]);
};
const debounceMocked = jest.spyOn(lodash, "debounce");
debounceMocked.mockImplementation((fn: any) => fn);
// top avoid the first middleware run which wud initiate all sagas.
jest.mock("sagas", () => ({
rootSaga: mockGenerator,
}));
// only the deafault exports are mocked to avoid overriding utilities exported out of them. defaults are marked to avoid worker initiation and page api calls in tests.
jest.mock("sagas/EvaluationsSaga", () => ({
...jest.requireActual("sagas/EvaluationsSaga"),
default: mockGenerator,
}));
jest.mock("sagas/PageSagas", () => ({
...jest.requireActual("sagas/PageSagas"),
default: mockGenerator,
}));
});
it("container drags when focused on", () => {
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = renderNestedComponent();
const containerWidget: any = component.container.querySelector(
".t--widget-containerwidget",
);
const draggableContainerWidget: any = component.container.querySelector(
".t--draggable-containerwidget",
);
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(3);
const initContainerWidgetPosition = {
left: containerWidget.style.left,
top: containerWidget.style.top,
};
act(() => {
fireEvent.mouseOver(draggableContainerWidget);
});
act(() => {
fireEvent.dragStart(draggableContainerWidget);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 100,
offsetY: 100,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
),
);
});
const movedContainerWidget: any = component.container.querySelector(
".t--widget-containerwidget",
);
const finalContainerWidgetPositions = {
left: movedContainerWidget.style.left,
top: movedContainerWidget.style.top,
};
expect(finalContainerWidgetPositions).not.toStrictEqual(
initContainerWidgetPosition,
);
});
it("nested widget drags when focused on", () => {
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = renderNestedComponent();
const textWidget: any = component.container.querySelector(
".t--widget-textwidget",
);
const draggableTextWidget: any = component.container.querySelector(
".t--draggable-textwidget",
);
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(3);
const initTextWidgetPosition = {
left: textWidget.style.left,
top: textWidget.style.top,
};
act(() => {
fireEvent.mouseOver(draggableTextWidget);
});
act(() => {
fireEvent.dragStart(draggableTextWidget);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 500,
offsetY: 500,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
),
);
});
const movedTextWidget: any = component.container.querySelector(
".t--widget-textwidget",
);
const finalTextWidgetPositions = {
left: movedTextWidget.style.left,
top: movedTextWidget.style.top,
};
expect(finalTextWidgetPositions).not.toStrictEqual(initTextWidgetPosition);
});
it("does not let disabledWidget drag and parent widget position stays same", () => {
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
mockGetIsFetchingPage.mockImplementation(() => false);
const component = renderNestedComponent();
const inputWidget: any = component.container.querySelector(
".t--widget-inputwidgetv2",
);
const draggableInputWidget: any = component.container.querySelector(
".t--draggable-inputwidgetv2",
);
const draggableContainerWidget: any = component.container.querySelector(
".t--draggable-containerwidget",
);
const containerWidget: any = component.container.querySelector(
".t--widget-containerwidget",
);
const initContainerWidgetPosition = {
left: containerWidget.style.left,
top: containerWidget.style.top,
};
const initInputWidgetPosition = {
left: inputWidget.style.left,
top: inputWidget.style.top,
};
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(3);
act(() => {
fireEvent.mouseOver(draggableContainerWidget);
});
act(() => {
fireEvent.mouseOver(draggableInputWidget);
});
act(() => {
fireEvent.dragStart(draggableInputWidget);
});
const mainCanvas: any = component.queryByTestId("div-dragarena-0");
if (mainCanvas) {
act(() => {
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
}),
{
offsetX: 500,
offsetY: 500,
},
),
);
fireEvent(
mainCanvas,
syntheticTestMouseEvent(
new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
}),
),
);
});
}
const movedInputWidget: any = component.container.querySelector(
".t--widget-inputwidgetv2",
);
const finalInputWidgetPositions = {
left: movedInputWidget.style.left,
top: movedInputWidget.style.top,
};
const movedContainerWidget: any = component.container.querySelector(
".t--widget-containerwidget",
);
const finalContainerWidgetPositions = {
left: movedContainerWidget.style.left,
top: movedContainerWidget.style.top,
};
expect(finalInputWidgetPositions).toStrictEqual(initInputWidgetPosition);
expect(initContainerWidgetPosition).toStrictEqual(
finalContainerWidgetPositions,
);
});
afterAll(() => jest.resetModules());
});