diff --git a/.github/workflows/build-client-server.yml b/.github/workflows/build-client-server.yml index 52253d4d03b4..550758e0fcbd 100644 --- a/.github/workflows/build-client-server.yml +++ b/.github/workflows/build-client-server.yml @@ -131,7 +131,6 @@ jobs: secrets: inherit with: pr: ${{fromJson(needs.file-check.outputs.pr)}} - matrix: ${{needs.file-check.outputs.matrix_count}} ci-test-limited-existing-docker-image: needs: [file-check] @@ -143,7 +142,6 @@ jobs: with: pr: ${{fromJson(needs.file-check.outputs.pr)}} previous-workflow-run-id: ${{ fromJson(needs.file-check.outputs.runId) }} - matrix: ${{ needs.file-check.outputs.matrix_count }} ci-test-limited-result: needs: [file-check, ci-test-limited] diff --git a/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/anvilDraggingSagas.test.ts b/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/anvilDraggingSagas.test.ts new file mode 100644 index 000000000000..fb1ffd3ab6b4 --- /dev/null +++ b/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/anvilDraggingSagas.test.ts @@ -0,0 +1,232 @@ +import { select } from "redux-saga/effects"; +import { addWidgetsSaga, moveWidgetsSaga } from "."; +import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; +import { generateReactKey } from "@shared/dsl/src/migrate/utils"; +import { LayoutComponentTypes } from "layoutSystems/anvil/utils/anvilTypes"; +import { expectSaga } from "redux-saga-test-plan"; +import { getWidgets } from "sagas/selectors"; +import { registerWidgets } from "WidgetProvider/factory/registrationHelper"; +import { SectionWidget } from "widgets/anvil/SectionWidget"; +import { ZoneWidget } from "widgets/anvil/ZoneWidget"; +import { WDSButtonWidget } from "widgets/wds/WDSButtonWidget"; +import { + getCanvasWidth, + getIsAutoLayoutMobileBreakPoint, +} from "selectors/editorSelectors"; +import { getCurrentlyOpenAnvilDetachedWidgets } from "../../modalSelectors"; +import { getDataTree } from "selectors/dataTreeSelectors"; +import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; +import { registerLayoutComponents } from "layoutSystems/anvil/utils/layouts/layoutUtils"; +import { getIsAnvilLayout } from "../../selectors"; +import { selectWidgetInitAction } from "actions/widgetSelectionActions"; +import { SelectionRequestType } from "sagas/WidgetSelectUtils"; +import { WDSModalWidget } from "widgets/wds/WDSModalWidget"; +import { generateMockDataWithTwoSections } from "./mockData.helper"; +import type { AnvilMoveWidgetsPayload } from "../../actions/actionTypes"; +import { + AnvilReduxActionTypes, + type AnvilNewWidgetsPayload, +} from "../../actions/actionTypes"; +import { AnvilDraggedWidgetTypesEnum } from "layoutSystems/anvil/editor/canvasArenas/types"; +import { + FlexLayerAlignment, + ResponsiveBehavior, +} from "layoutSystems/common/utils/constants"; +import { mockAnvilHighlightInfo } from "mocks/mockHighlightInfo"; + +describe("", () => { + beforeAll(() => { + registerLayoutComponents(); + registerWidgets([ + SectionWidget, + ZoneWidget, + WDSButtonWidget, + WDSModalWidget, + ]); + }); + // Successfully adds a new widget to the main canvas + it("should successfully add a new widget to the main canvas", async () => { + const mainCanvasLayoutId = generateReactKey(); + const newWidgetId = generateReactKey(); + const allWidgets: any = { + [MAIN_CONTAINER_WIDGET_ID]: { + widgetName: "Main Container", + widgetId: MAIN_CONTAINER_WIDGET_ID, + children: [], + layout: [ + { + layoutId: mainCanvasLayoutId, + layoutType: LayoutComponentTypes.ALIGNED_LAYOUT_COLUMN, + layout: [], + }, + ], + }, + }; + const payload: AnvilNewWidgetsPayload = { + dragMeta: { + draggedOn: "MAIN_CANVAS", + draggedWidgetTypes: AnvilDraggedWidgetTypesEnum.WIDGETS, + }, + highlight: mockAnvilHighlightInfo({ + alignment: FlexLayerAlignment.Start, + canvasId: MAIN_CONTAINER_WIDGET_ID, + layoutId: mainCanvasLayoutId, + layoutOrder: [mainCanvasLayoutId], + }), + newWidget: { + width: 100, + height: 50, + newWidgetId, + type: "WDS_BUTTON_WIDGET", + detachFromLayout: false, + }, + }; + const actionPayload = { + type: AnvilReduxActionTypes.ANVIL_ADD_NEW_WIDGET, + payload, + }; + const { effects } = await expectSaga(addWidgetsSaga, actionPayload) + .provide([ + [select(getWidgets), allWidgets], + [select(getCanvasWidth), 100], + [select(getIsAutoLayoutMobileBreakPoint), false], + [select(getCurrentlyOpenAnvilDetachedWidgets), []], + [select(getDataTree), {}], + [select(getLayoutSystemType), "ANVIL"], + [select(getIsAnvilLayout), true], + ]) + .run(); + const widgetSelectPutEffect = effects.put[effects.put.length - 1]; + expect(widgetSelectPutEffect.payload.action).toEqual( + selectWidgetInitAction(SelectionRequestType.Create, [newWidgetId]), + ); + const updateWidgetsPutEffect = effects.put[effects.put.length - 2]; + expect(updateWidgetsPutEffect.payload.action.type).toBe("UPDATE_LAYOUT"); + // check if new widget was added to main canvas by wrapping it in a section and zone + const updatedWidgets = + updateWidgetsPutEffect.payload.action.payload.widgets; + const mainCanvasWidget = updatedWidgets[MAIN_CONTAINER_WIDGET_ID]; + const sectionWidgetId = mainCanvasWidget.children[0]; + const sectionWidget = updatedWidgets[sectionWidgetId]; + const zoneWidgetId = sectionWidget.children[0]; + const zoneWidget = updatedWidgets[zoneWidgetId]; + expect(zoneWidget.children).toContain(newWidgetId); + }); + it("should successfully add a new modal widget to the main canvas", async () => { + const mainCanvasLayoutId = generateReactKey(); + const newModalId = generateReactKey(); + const allWidgets: any = { + [MAIN_CONTAINER_WIDGET_ID]: { + widgetName: "Main Container", + widgetId: MAIN_CONTAINER_WIDGET_ID, + children: [], + layout: [ + { + layoutId: mainCanvasLayoutId, + layoutType: LayoutComponentTypes.ALIGNED_LAYOUT_COLUMN, + layout: [], + }, + ], + }, + }; + const payload: AnvilNewWidgetsPayload = { + dragMeta: { + draggedOn: "MAIN_CANVAS", + draggedWidgetTypes: AnvilDraggedWidgetTypesEnum.WIDGETS, + }, + highlight: mockAnvilHighlightInfo({ + alignment: FlexLayerAlignment.Start, + canvasId: MAIN_CONTAINER_WIDGET_ID, + layoutId: mainCanvasLayoutId, + layoutOrder: [mainCanvasLayoutId], + }), + newWidget: { + width: 100, + height: 50, + newWidgetId: newModalId, + type: "WDS_MODAL_WIDGET", + detachFromLayout: true, + }, + }; + const actionPayload = { + type: AnvilReduxActionTypes.ANVIL_ADD_NEW_WIDGET, + payload, + }; + + const { effects } = await expectSaga(addWidgetsSaga, actionPayload) + .provide([ + [select(getWidgets), allWidgets], + [select(getCanvasWidth), 100], + [select(getIsAutoLayoutMobileBreakPoint), false], + [select(getCurrentlyOpenAnvilDetachedWidgets), []], + [select(getDataTree), {}], + [select(getLayoutSystemType), "ANVIL"], + [select(getIsAnvilLayout), true], + ]) + .run(); + const widgetSelectPutEffect = effects.put[effects.put.length - 1]; + expect(widgetSelectPutEffect.payload.action).toEqual( + selectWidgetInitAction(SelectionRequestType.Create, [newModalId]), + ); + const updateWidgetsPutEffect = effects.put[effects.put.length - 2]; + expect(updateWidgetsPutEffect.payload.action.type).toBe("UPDATE_LAYOUT"); + // check if new widget was added to main canvas by wrapping it in a section and zone + const updatedWidgets = + updateWidgetsPutEffect.payload.action.payload.widgets; + const mainCanvasWidget = updatedWidgets[MAIN_CONTAINER_WIDGET_ID]; + const modalWidgetId = mainCanvasWidget.children[0]; + expect(modalWidgetId).toContain(newModalId); + }); + + it("should successfully move widget to the main canvas", async () => { + const { allWidgets, mainCanvasLayoutId, section1Id, section2Id } = + generateMockDataWithTwoSections(); + const payload: AnvilMoveWidgetsPayload = { + dragMeta: { + draggedOn: "MAIN_CANVAS", + draggedWidgetTypes: AnvilDraggedWidgetTypesEnum.SECTION, + }, + movedWidgets: [ + { + widgetId: section2Id, + type: "SECTION_WIDGET", + parentId: MAIN_CONTAINER_WIDGET_ID, + responsiveBehavior: ResponsiveBehavior.Fill, + }, + ], + highlight: mockAnvilHighlightInfo({ + alignment: FlexLayerAlignment.Start, + rowIndex: 0, + canvasId: MAIN_CONTAINER_WIDGET_ID, + layoutId: mainCanvasLayoutId, + layoutOrder: [mainCanvasLayoutId], + }), + }; + const actionPayload = { + type: AnvilReduxActionTypes.ANVIL_MOVE_WIDGET, + payload, + }; + const { effects } = await expectSaga(moveWidgetsSaga, actionPayload) + .provide([ + [select(getWidgets), allWidgets], + [select(getCanvasWidth), 100], + [select(getIsAutoLayoutMobileBreakPoint), false], + [select(getCurrentlyOpenAnvilDetachedWidgets), []], + [select(getDataTree), {}], + [select(getLayoutSystemType), "ANVIL"], + [select(getIsAnvilLayout), true], + ]) + .run(); + const updateWidgetsPutEffect = effects.put[effects.put.length - 1]; + expect(updateWidgetsPutEffect.payload.action.type).toBe("UPDATE_LAYOUT"); + // expect section2 to be moved to the first position in layout + const updatedWidgets = + updateWidgetsPutEffect.payload.action.payload.widgets; + const mainCanvasWidget = updatedWidgets[MAIN_CONTAINER_WIDGET_ID]; + const mainCanvasLayout = mainCanvasWidget.layout[0]; + const firstWidgetRow = mainCanvasLayout.layout[0]; + const secondWidgetRow = mainCanvasLayout.layout[1]; + expect(firstWidgetRow.layout[0].widgetId).toBe(section2Id); + expect(secondWidgetRow.layout[0].widgetId).toBe(section1Id); + }); +}); diff --git a/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas.ts b/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/index.ts similarity index 96% rename from app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas.ts rename to app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/index.ts index fbaea2af140b..b8a8581ca605 100644 --- a/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas.ts +++ b/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/index.ts @@ -10,12 +10,12 @@ import type { WidgetLayoutProps, } from "layoutSystems/anvil/utils/anvilTypes"; import { getWidget, getWidgets } from "sagas/selectors"; -import { addWidgetsToPreset } from "../../utils/layouts/update/additionUtils"; +import { addWidgetsToPreset } from "../../../utils/layouts/update/additionUtils"; import type { AnvilMoveWidgetsPayload, AnvilNewWidgetsPayload, -} from "../actions/actionTypes"; -import { AnvilReduxActionTypes } from "../actions/actionTypes"; +} from "../../actions/actionTypes"; +import { AnvilReduxActionTypes } from "../../actions/actionTypes"; import { generateDefaultLayoutPreset } from "layoutSystems/anvil/layoutComponents/presets/DefaultLayoutPreset"; import { selectWidgetInitAction } from "actions/widgetSelectionActions"; import { SelectionRequestType } from "sagas/WidgetSelectUtils"; @@ -39,7 +39,7 @@ import { addNewWidgetToDsl, getCreateWidgetPayload, } from "layoutSystems/anvil/utils/widgetAdditionUtils"; -import { updateAndSaveAnvilLayout } from "../../utils/anvilChecksUtils"; +import { updateAndSaveAnvilLayout } from "../../../utils/anvilChecksUtils"; import { moveWidgetsToZone } from "layoutSystems/anvil/utils/layouts/update/zoneUtils"; // Function to retrieve highlighting information for the last row in the main canvas layout @@ -201,7 +201,9 @@ export function* addNewChildToDSL( } // function to handle the addition of new widgets to the Anvil layout -function* addWidgetsSaga(actionPayload: ReduxAction) { +export function* addWidgetsSaga( + actionPayload: ReduxAction, +) { try { const start = performance.now(); @@ -297,7 +299,9 @@ function* addWidgetToGenericLayout( * Remove widgets from current parents and layouts. * Add to new parent and layout. */ -function* moveWidgetsSaga(actionPayload: ReduxAction) { +export function* moveWidgetsSaga( + actionPayload: ReduxAction, +) { try { const start = performance.now(); const { diff --git a/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/mockData.helper.ts b/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/mockData.helper.ts new file mode 100644 index 000000000000..559884b8a082 --- /dev/null +++ b/app/client/src/layoutSystems/anvil/integrations/sagas/anvilDraggingSagas/mockData.helper.ts @@ -0,0 +1,113 @@ +import { generateReactKey } from "@shared/dsl/src/migrate/utils"; +import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; +import { LayoutComponentTypes } from "layoutSystems/anvil/utils/anvilTypes"; +import { FlexLayerAlignment } from "layoutSystems/common/utils/constants"; + +export const generateMockDataWithTwoSections = () => { + const mainCanvasLayoutId = generateReactKey(); + const section1Id = generateReactKey(); + const section2Id = generateReactKey(); + const zone1Id = generateReactKey(); + const zone2Id = generateReactKey(); + const section1Layout = { + layoutType: LayoutComponentTypes.SECTION, + layout: [ + { + widgetId: zone1Id, + alignment: FlexLayerAlignment.Start, + widgetType: "ZONE_WIDGET", + }, + ], + }; + const section2Layout = { + layoutType: LayoutComponentTypes.SECTION, + layout: [ + { + widgetId: zone2Id, + alignment: FlexLayerAlignment.Start, + widgetType: "ZONE_WIDGET", + }, + ], + }; + const allWidgets: any = { + [MAIN_CONTAINER_WIDGET_ID]: { + widgetName: "Main Container", + widgetId: MAIN_CONTAINER_WIDGET_ID, + children: [section1Id, section2Id], + layout: [ + { + layoutId: mainCanvasLayoutId, + layoutType: LayoutComponentTypes.ALIGNED_LAYOUT_COLUMN, + childTemplate: { + insertChild: true, + layoutId: "", + layoutType: LayoutComponentTypes.WIDGET_ROW, + layout: [], + }, + layout: [ + { + layoutType: LayoutComponentTypes.WIDGET_ROW, + layout: [ + { + widgetId: section1Id, + alignment: FlexLayerAlignment.Start, + widgetType: "SECTION_WIDGET", + }, + ], + }, + { + layoutType: LayoutComponentTypes.WIDGET_ROW, + layout: [ + { + widgetId: section2Id, + alignment: FlexLayerAlignment.Start, + widgetType: "SECTION_WIDGET", + }, + ], + }, + ], + }, + ], + }, + [section1Id]: { + widgetName: "Section 1", + type: "SECTION_WIDGET", + widgetId: section1Id, + children: [zone1Id], + layout: [section1Layout], + zoneCount: 1, + parentId: MAIN_CONTAINER_WIDGET_ID, + }, + [section2Id]: { + widgetName: "Section 2", + type: "SECTION_WIDGET", + widgetId: section2Id, + children: [zone2Id], + layout: [section2Layout], + zoneCount: 1, + parentId: MAIN_CONTAINER_WIDGET_ID, + }, + [zone1Id]: { + widgetName: "Zone 1", + type: "ZONE_WIDGET", + widgetId: zone1Id, + children: [], + parentId: section1Id, + }, + [zone2Id]: { + widgetName: "Zone 2", + type: "ZONE_WIDGET", + widgetId: zone2Id, + children: [], + parentId: section2Id, + }, + }; + return { + allWidgets, + mainCanvasLayoutId, + section1Id, + section2Id, + zone1Id, + zone2Id, + }; +}; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java index fccb245d80ea..3b61de875c91 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java @@ -78,8 +78,7 @@ public class PageDTO { @JsonView(Views.Public.class) DefaultResources defaultResources; - // TODO: get this clarified for GIT annotation - @JsonView({Views.Public.class, Git.class}) + @JsonView(Views.Public.class) Map> dependencyMap; public void sanitiseToExportDBObject() {