Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions app/client/src/WidgetProvider/factory/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class WidgetFactory {
Partial<WidgetProps> & WidgetConfigProps & { type: string }
> = new Map();

static widgetDefaultPropertiesMap: Map<string, Record<string, unknown>> =
new Map();

static widgetsMap: Map<WidgetType, typeof BaseWidget> = new Map();

static widgetBuilderMap: Map<WidgetType, any> = new Map();
Expand Down Expand Up @@ -132,6 +135,18 @@ class WidgetFactory {
onCanvasUI,
};

// When adding widgets to canvas in Anvil, we don't need all of configured properties
// (See _config object)
// and that should ideally be the case for Fixed mode widgets as well
// So, creating this map to use in WidgetAdditionSagas for both Fixed
// and Anvil.
// Before this we were using "ALL" configured properties when creating
// the newly added widget. This lead to many extra properties being added
// to the DSL
WidgetFactory.widgetDefaultPropertiesMap.set(
widget.type,
Object.freeze({ ...defaultConfig }),
);
WidgetFactory.widgetConfigMap.set(widget.type, Object.freeze(_config));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { select } from "redux-saga/effects";
import { addWidgetsSaga, moveWidgetsSaga } from ".";
import { 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";
Expand Down Expand Up @@ -33,6 +33,7 @@ import {
ResponsiveBehavior,
} from "layoutSystems/common/utils/constants";
import { mockAnvilHighlightInfo } from "mocks/mockHighlightInfo";
import { addWidgetsSaga } from "../anvilWidgetAdditionSagas";

describe("", () => {
beforeAll(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { WidgetProps } from "widgets/BaseWidget";
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
import { FlexLayerAlignment } from "layoutSystems/common/utils/constants";
import { select } from "redux-saga/effects";
import { getWidget } from "sagas/selectors";

// Function to retrieve highlighting information for the last row in the main canvas layout
export function* getMainCanvasLastRowHighlight() {
// Retrieve the main canvas widget
const mainCanvas: WidgetProps = yield select(
getWidget,
MAIN_CONTAINER_WIDGET_ID,
);

const layoutId: string = mainCanvas.layout[0].layoutId;
const layoutOrder = [layoutId];
const rowIndex = mainCanvas.layout[0].layout.length;

// Return the highlighting information for the last row in the main canvas
return {
canvasId: MAIN_CONTAINER_WIDGET_ID,
layoutOrder,
rowIndex,
posX: 0,
posY: 0,
alignment: FlexLayerAlignment.Start,
dropZone: {},
height: 0,
width: 0,
isVertical: false,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,13 @@ import { all, call, put, select, takeLatest } from "redux-saga/effects";
import type {
AnvilHighlightInfo,
DraggedWidget,
WidgetLayoutProps,
} from "layoutSystems/anvil/utils/anvilTypes";
import { getWidget, getWidgets } from "sagas/selectors";
import { addWidgetsToPreset } from "../../../utils/layouts/update/additionUtils";
import type {
AnvilMoveWidgetsPayload,
AnvilNewWidgetsPayload,
} from "../../actions/actionTypes";
import { getWidgets } from "sagas/selectors";
import type { AnvilMoveWidgetsPayload } 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";
import {
addDetachedWidgetToMainCanvas,
addWidgetsToMainCanvasLayout,
moveWidgetsToMainCanvas,
} from "layoutSystems/anvil/utils/layouts/update/mainCanvasLayoutUtils";
import type { WidgetProps } from "widgets/BaseWidget";
import {
GridDefaults,
MAIN_CONTAINER_WIDGET_ID,
} from "constants/WidgetConstants";
import { FlexLayerAlignment } from "layoutSystems/common/utils/constants";
import {
addWidgetsToSection,
moveWidgetsToSection,
} from "layoutSystems/anvil/utils/layouts/update/sectionUtils";
import { WDS_V2_WIDGET_MAP } from "widgets/wds/constants";
import {
addNewWidgetToDsl,
getCreateWidgetPayload,
} from "layoutSystems/anvil/utils/widgetAdditionUtils";
import { moveWidgetsToMainCanvas } from "layoutSystems/anvil/utils/layouts/update/mainCanvasLayoutUtils";

import { moveWidgetsToSection } from "layoutSystems/anvil/utils/layouts/update/sectionUtils";
import { updateAndSaveAnvilLayout } from "../../../utils/anvilChecksUtils";
import {
isRedundantZoneWidget,
Expand All @@ -49,259 +24,6 @@ import {
import { severTiesFromParents } from "../../../utils/layouts/update/moveUtils";
import { widgetChildren } from "../../../utils/layouts/widgetUtils";

// Function to retrieve highlighting information for the last row in the main canvas layout
export function* getMainCanvasLastRowHighlight() {
// Retrieve the main canvas widget
const mainCanvas: WidgetProps = yield select(
getWidget,
MAIN_CONTAINER_WIDGET_ID,
);

// Extract the layout ID and row index for the last row in the main canvas
const layoutId: string = mainCanvas.layout[0].layoutId;
const layoutOrder = [layoutId];
const rowIndex = mainCanvas.layout[0].layout.length;

// Return the highlighting information for the last row in the main canvas
return {
canvasId: MAIN_CONTAINER_WIDGET_ID,
layoutOrder,
rowIndex,
posX: 0,
posY: 0,
alignment: FlexLayerAlignment.Start,
dropZone: {},
height: 0,
width: 0,
isVertical: false,
};
}

// function to handle adding suggested widgets to the Anvil canvas
function* addSuggestedWidgetsAnvilSaga(
actionPayload: ReduxAction<{
newWidget: {
newWidgetId: string;
type: string;
rows?: number;
columns?: number;
props: WidgetProps;
detachFromLayout: boolean;
};
}>,
) {
const { newWidget } = actionPayload.payload;

// Find the corresponding WDS entry for the given widget type
const wdsEntry = Object.entries(WDS_V2_WIDGET_MAP).find(
([legacyType]) => legacyType === newWidget.type,
);

// If a matching WDS entry is found, proceed with adding the suggested widget
if (wdsEntry) {
// Extract the WDS type for the suggested widget
const [, wdsType] = wdsEntry;

// Define parameters for the new widget based on the WDS type and provided dimensions
const newWidgetParams = {
width: (newWidget.rows || 0 / GridDefaults.DEFAULT_GRID_COLUMNS) * 100,
height: newWidget.columns || 0 * GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
newWidgetId: newWidget.newWidgetId,
parentId: MAIN_CONTAINER_WIDGET_ID,
type: wdsType,
detachFromLayout: newWidget.detachFromLayout,
};

// Get highlighting information for the last row in the main canvas
const mainCanvasHighLight: AnvilHighlightInfo = yield call(
getMainCanvasLastRowHighlight,
);

// Add the new widget to the DSL
const updatedWidgets: CanvasWidgetsReduxState = yield call(
addNewChildToDSL,
mainCanvasHighLight,
newWidgetParams,
true,
false,
);

// Update the widget properties with the properties provided in the action payload
updatedWidgets[newWidgetParams.newWidgetId] = {
...updatedWidgets[newWidgetParams.newWidgetId],
...newWidget.props,
};

// Save the updated Anvil layout
yield call(updateAndSaveAnvilLayout, updatedWidgets);

// Select the added widget
yield put(
selectWidgetInitAction(SelectionRequestType.One, [
newWidgetParams.newWidgetId,
]),
);
}
}

// function to add a new child widget to the DSL
export function* addNewChildToDSL(
highlight: AnvilHighlightInfo, // Highlight information for the drop zone
newWidget: {
width: number;
height: number;
newWidgetId: string;
type: string;
detachFromLayout: boolean;
},
isMainCanvas: boolean, // Indicates if the drop zone is the main canvas
isSection: boolean, // Indicates if the drop zone is a section
) {
const { alignment, canvasId } = highlight;
const allWidgets: CanvasWidgetsReduxState = yield select(getWidgets);

const parentWidgetWithLayout = allWidgets[canvasId];
let updatedWidgets: CanvasWidgetsReduxState = { ...allWidgets };

const draggedWidgets: WidgetLayoutProps[] = [
{
alignment,
widgetId: newWidget.newWidgetId,
widgetType: newWidget.type,
},
];

if (newWidget.detachFromLayout) {
updatedWidgets = yield call(addDetachedWidgetToMainCanvas, updatedWidgets, {
widgetId: newWidget.newWidgetId,
type: newWidget.type,
});
} else {
// Handle different scenarios based on the drop zone type (main canvas, section, or generic layout)
if (!!isMainCanvas || parentWidgetWithLayout.detachFromLayout) {
updatedWidgets = yield call(
addWidgetsToMainCanvasLayout,
updatedWidgets,
draggedWidgets,
highlight,
);
} else if (!!isSection) {
const res: { canvasWidgets: CanvasWidgetsReduxState } = yield call(
addWidgetsToSection,
updatedWidgets,
draggedWidgets,
highlight,
updatedWidgets[canvasId],
);
updatedWidgets = res.canvasWidgets;
} else {
updatedWidgets = yield call(
addWidgetToGenericLayout,
updatedWidgets,
draggedWidgets,
highlight,
newWidget,
);
}
}
return updatedWidgets;
}

// function to handle the addition of new widgets to the Anvil layout
export function* addWidgetsSaga(
actionPayload: ReduxAction<AnvilNewWidgetsPayload>,
) {
try {
const start = performance.now();

const {
dragMeta: { draggedOn },
highlight,
newWidget,
} = actionPayload.payload;
// Check if the drop zone is the main canvas
const isMainCanvas = draggedOn === "MAIN_CANVAS";
// Check if the drop zone is a section
const isSection = draggedOn === "SECTION";

// Call the addNewChildToDSL saga to perform the actual addition of the new widget to the DSL
const updatedWidgets: CanvasWidgetsReduxState = yield call(
addNewChildToDSL,
highlight,
newWidget,
!!isMainCanvas,
!!isSection,
);

// Save the updated Anvil layout
yield call(updateAndSaveAnvilLayout, updatedWidgets);

// Select the newly added widget
yield put(
selectWidgetInitAction(SelectionRequestType.Create, [
newWidget.newWidgetId,
]),
);

log.debug("Anvil: add new widget took", performance.now() - start, "ms");
} catch (error) {
yield put({
type: ReduxActionErrorTypes.WIDGET_OPERATION_ERROR,
payload: {
action: AnvilReduxActionTypes.ANVIL_ADD_NEW_WIDGET,
error,
},
});
}
}

function* addWidgetToGenericLayout(
allWidgets: CanvasWidgetsReduxState,
draggedWidgets: WidgetLayoutProps[],
highlight: AnvilHighlightInfo,
newWidget: {
width: number;
height: number;
newWidgetId: string;
type: string;
},
) {
let updatedWidgets: CanvasWidgetsReduxState = { ...allWidgets };
const canvasWidget = updatedWidgets[highlight.canvasId];
const canvasLayout = canvasWidget.layout
? canvasWidget.layout
: generateDefaultLayoutPreset();

/**
* Create widget and add to parent.
*/
updatedWidgets = yield call(
addNewWidgetToDsl,
updatedWidgets,
getCreateWidgetPayload(
newWidget.newWidgetId,
newWidget.type,
canvasWidget.widgetId,
),
);
/**
* Also add it to parent's layout.
*/
return {
...updatedWidgets,
[canvasWidget.widgetId]: {
...updatedWidgets[canvasWidget.widgetId],
layout: addWidgetsToPreset(canvasLayout, highlight, draggedWidgets),
},
[newWidget.newWidgetId]: {
...updatedWidgets[newWidget.newWidgetId],
// This is a temp fix, widget dimensions will be self computed by widgets
height: newWidget.height,
width: newWidget.width,
},
};
}

/**
* Remove widgets from current parents and layouts.
* Add to new parent and layout.
Expand Down Expand Up @@ -421,11 +143,6 @@ export function handleDeleteRedundantZones(

export default function* anvilDraggingSagas() {
yield all([
takeLatest(AnvilReduxActionTypes.ANVIL_ADD_NEW_WIDGET, addWidgetsSaga),
takeLatest(AnvilReduxActionTypes.ANVIL_MOVE_WIDGET, moveWidgetsSaga),
takeLatest(
AnvilReduxActionTypes.ANVIL_ADD_SUGGESTED_WIDGET,
addSuggestedWidgetsAnvilSaga,
),
]);
}
Loading