Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: fix blueprint operation inconsistency for zone #36980

Merged
merged 6 commits into from
Oct 25, 2024

Conversation

jsartisan
Copy link
Contributor

@jsartisan jsartisan commented Oct 19, 2024

In anvil, when widgets are dropped on canvas, we create a zone which has visual separation marked as true by default.
Now, There is a usecase for the chat widget in which we want to modify the zones Visual separation` to false on creation of zone.

The code for bleuprint operation for chat widget would like this:

blueprint: {
    operations: [
      {
        type: BlueprintOperationTypes.MODIFY_PROPS,
        fn: (
          widget: FlattenedWidgetProps,
          widgets: CanvasWidgetsReduxState,
          parent: FlattenedWidgetProps,
          layoutSystemType: LayoutSystemTypes,
        ) => {
          if (layoutSystemType !== LayoutSystemTypes.ANVIL) return [];

          const updates: UpdatePropertyArgs[] = [];
          const parentId = widget.parentId;

          if (!parentId) return updates;

          const parentWidget = widgets[parentId];

          // we want to proceed only if the parent is a zone widget and has no children
          if (
            parentWidget.children?.length === 0 &&
            parentWidget.type === "ZONE_WIDGET"
          ) {
            updates.push({
              widgetId: parentId,
              propertyName: "elevatedBackground",
              propertyValue: false,
            });
          }

          return updates;
        },
      },
    ],
  },

This should work fine, but in the code where we create zone and attaching widgets to it, after running the blueprint operations, we were not using the correct updated zone that returned from blueprint operations of the child widgets. This PR uses the correct zone.

Also there is a case where blueprint operation is not able to update the existing widgets because all properties of existing widgets were readonly. So cloned the widgets from redux before passing to widget addition saga functions.

/ok-to-test tags="@tag.All"

Summary by CodeRabbit

  • New Features

    • Improved clarity in widget handling by renaming parameters related to dragged widgets.
    • Streamlined the process of adding widgets to zones by simplifying parameter structures.
  • Bug Fixes

    • Enhanced immutability in widget property updates within the state management process.
  • Style

    • Updated CSS styles for the .markdown class, removing unnecessary pseudo-elements for improved formatting.

Tip

🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/11474751370
Commit: 8a385ee
Cypress dashboard.
Tags: @tag.All
Spec:


Wed, 23 Oct 2024 09:47:24 UTC

Summary by CodeRabbit

  • New Features

    • Improved clarity in widget handling by renaming parameters related to dragged widgets.
    • Enhanced functionality for adding widgets to zones by simplifying the data structure used.
    • Implemented safer state manipulation for widget addition using a deep copy approach.
  • Bug Fixes

    • Addressed potential issues with direct state mutation during widget addition.
  • Style

    • Updated CSS styles for the Markdown component by removing unnecessary pseudo-elements.

@jsartisan jsartisan requested a review from a team as a code owner October 19, 2024 05:54
Copy link
Contributor

coderabbitai bot commented Oct 19, 2024

Walkthrough

The changes in this pull request involve renaming parameters for clarity in the sectionUtils.ts and zoneUtils.ts files, specifically changing widgets to draggedWidgets. Additionally, the zoneUtils.ts file has been updated to simplify how zone properties are handled by using widget IDs instead of entire objects. The CSS styles in styles.module.css have been modified to remove specific pseudo-elements. Lastly, the anvilWidgetAdditionSagas/index.ts file has been updated to enhance widget state management by incorporating the klona library for deep copying.

Changes

File Path Change Summary
app/client/src/layoutSystems/anvil/utils/layouts/update/sectionUtils.ts Renamed parameter widgets to draggedWidgets in createSectionAndAddWidget and addWidgetsToSection functions for clarity. Logic updated to use the renamed parameter consistently.
app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts Updated createZoneAndAddWidgets to pass widgetId instead of zoneProps. Changed addWidgetsToZone to use zoneWidgetId instead of zone. Simplified access to properties and updated return statements accordingly.
app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css Removed ::after and ::before pseudo-elements from .markdown class, preserving other styles.
app/client/src/layoutSystems/anvil/integrations/sagas/anvilWidgetAdditionSagas/index.ts Added klona library for deep copying widget state. Renamed variable allWidgets to allWidgetsFromRedux in getUpdatedListOfWidgetsAfterAddingNewWidget function. Introduced a new variable for the deep copy of the widget state. Functionality for managing widget addition updated accordingly.

Possibly related PRs

Suggested labels

Bug, Enhancement, Anvil Pod

Suggested reviewers

  • riodeuno

🎉 In the code we trust, with clarity we adjust,
Widgets now drag, no longer a shrug.
From zones to sections, our logic's in line,
With klona in hand, our states will align.
CSS tidied, no more clutter in sight,
In the realm of code, everything feels right! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the skip-changelog Adding this label to a PR prevents it from being listed in the changelog label Oct 19, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
app/client/src/layoutSystems/anvil/utils/layouts/update/sectionUtils.ts (1)

Line range hint 62-62: Consider renaming parameter in splitWidgets for consistency

To maintain consistency with the recent changes, consider renaming the widgets parameter in the splitWidgets function to draggedWidgets.

Here's the suggested change:

-export function splitWidgets(widgets: WidgetLayoutProps[]): WidgetLayoutProps[][] {
+export function splitWidgets(draggedWidgets: WidgetLayoutProps[]): WidgetLayoutProps[][] {

Don't forget to update the function body to use the new parameter name.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9a315ea and 311aae8.

📒 Files selected for processing (3)
  • app/client/src/layoutSystems/anvil/utils/layouts/update/sectionUtils.ts (2 hunks)
  • app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts (4 hunks)
  • app/client/src/sagas/WidgetBlueprintSagas.ts (1 hunks)
🧰 Additional context used
🪛 Biome
app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts

[error] 87-87: children is assigned to itself.

This is where is assigned.

(lint/correctness/noSelfAssign)

🔇 Additional comments (9)
app/client/src/layoutSystems/anvil/utils/layouts/update/sectionUtils.ts (3)

22-22: Improved parameter naming in createSectionAndAddWidget

The renaming of widgets to draggedWidgets enhances code clarity. It now explicitly indicates that the function deals with dragged widgets.


51-51: Consistent parameter naming in addWidgetsToSection

The parameter renaming from widgets to draggedWidgets in this function maintains consistency with the changes made in createSectionAndAddWidget. This improves overall code readability.


Line range hint 1-240: Overall assessment: Improved naming conventions

The changes in this file enhance code clarity by consistently renaming parameters to better reflect their purpose. The modifications are straightforward and do not alter the logic of the functions. With the suggested update to the splitWidgets function, the file will maintain a high level of consistency in its naming conventions.

app/client/src/sagas/WidgetBlueprintSagas.ts (1)

137-140: Improved immutability in state updates.

The change enhances the immutability of state updates by using the spread operator. This aligns with Redux best practices and functional programming principles.

app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts (5)

61-61: Function call updated correctly

Passing zoneProps.widgetId to addWidgetsToZone aligns with the updated function signature.


71-71: Function signature modified appropriately

addWidgetsToZone now takes zoneWidgetId instead of the entire zone object, simplifying the function parameters.


74-74: Accessing layout via zoneWidgetId

Using updatedWidgets[zoneWidgetId].layout is consistent with the parameter change.


128-128: Updating zone layout correctly

Assigning the updated zoneLayout back to updatedWidgets[zoneWidgetId].layout looks good.


131-132: Return statement updated appropriately

Returning updatedWidgets[zoneWidgetId] as the zone simplifies the data handling.

@@ -86,7 +84,7 @@ export function* addWidgetsToZone(
zoneWidgetId,
draggedWidgets,
);
zoneProps.children = updatedWidgets[zoneWidgetId].children;
updatedWidgets[zoneWidgetId].children = updatedWidgets[zoneWidgetId].children;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the updateDraggedWidgets can update the zone in the blueprint operation as well, but we didn't use updatedWidgets's zone. We just worked on the zone that we got in params.
This is the source of inconsistency.

@@ -134,8 +134,10 @@ export function* executeWidgetBlueprintOperations(

updatePropertyPayloads &&
updatePropertyPayloads.forEach((params: UpdatePropertyArgs) => {
widgets[params.widgetId][params.propertyName] =
params.propertyValue;
widgets[params.widgetId] = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For cases where widgets are already present in redux, the objects are frozen and the fields are readonly. So we couldn't update them. used the spread operator to bypass that. Hoping this won't cause any issue.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts (1)

Line range hint 112-112: Use updatedWidgets instead of allWidgets when adding new widgets.

In the updateDraggedWidgets function, you're passing allWidgets to addNewAnvilWidgetToDSL, but updatedWidgets may have been modified earlier in the loop. To ensure consistency and include all prior updates, consider passing updatedWidgets instead.

Apply this diff to fix the issue:

-    updatedWidgets = yield addNewAnvilWidgetToDSL(allWidgets, {
+    updatedWidgets = yield addNewAnvilWidgetToDSL(updatedWidgets, {
       widgetId,
       type: widgetType,
       parentId: zoneWidgetId,
     });
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 311aae8 and d7b7cf5.

📒 Files selected for processing (1)
  • app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts (5 hunks)
🧰 Additional context used
🪛 Biome
app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts

[error] 87-87: children is assigned to itself.

This is where is assigned.

(lint/correctness/noSelfAssign)

🔇 Additional comments (4)
app/client/src/layoutSystems/anvil/utils/layouts/update/zoneUtils.ts (4)

61-61: Change is appropriate: updated parameter reflects the new function signature.

Passing zoneProps.widgetId to addWidgetsToZone aligns with the updated function signature that now accepts zoneWidgetId instead of the entire zone object.


71-71: Function signature updated correctly.

Changing the parameter from zone: WidgetProps to zoneWidgetId: string simplifies the function and reduces unnecessary data passing.


87-87: Remove redundant self-assignment.

Line 87 assigns children to itself, which is unnecessary and can be safely removed.

🧰 Tools
🪛 Biome

[error] 87-87: children is assigned to itself.

This is where is assigned.

(lint/correctness/noSelfAssign)


217-217: Confirm that canvasId correctly references the zone widget.

In the moveWidgetsToNewLayout function, you're using widgets[canvasId] to obtain zone, and then passing zone.widgetId to addWidgetsToZone. Ensure that canvasId correctly references the intended zone widget to avoid potential issues with incorrect widget references.

@@ -19,7 +19,7 @@ import { addNewAnvilWidgetToDSL } from "layoutSystems/anvil/integrations/sagas/a
export function* createSectionAndAddWidget(
allWidgets: CanvasWidgetsReduxState,
highlight: AnvilHighlightInfo,
widgets: WidgetLayoutProps[],
draggedWidgets: WidgetLayoutProps[],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used better contextual name to avoid confusion.
widgets felt like it is all the widgets but it is only the dragged widgets.

@jsartisan jsartisan requested a review from riodeuno October 21, 2024 05:04
@KelvinOm KelvinOm added the ok-to-test Required label for CI label Oct 21, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
app/client/src/layoutSystems/anvil/integrations/sagas/anvilWidgetAdditionSagas/index.ts (1)

113-114: LGTM: Improved state handling with deep cloning.

The renaming and use of klona for deep cloning enhance state management. Consider using a more descriptive name for the cloned state, such as mutableWidgets, to further clarify its purpose.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 26279c8 and 8a385ee.

📒 Files selected for processing (1)
  • app/client/src/layoutSystems/anvil/integrations/sagas/anvilWidgetAdditionSagas/index.ts (2 hunks)
🧰 Additional context used
🔇 Additional comments (1)
app/client/src/layoutSystems/anvil/integrations/sagas/anvilWidgetAdditionSagas/index.ts (1)

30-30: LGTM: Good choice for deep cloning.

The addition of klona is a solid choice for creating deep copies of objects, which aligns well with immutable state management practices in Redux.

@jsartisan jsartisan added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels Oct 22, 2024
@@ -109,7 +110,8 @@ export function* getUpdatedListOfWidgetsAfterAddingNewWidget(
isSection: boolean, // Indicates if the drop zone is a section
) {
const { alignment, canvasId } = highlight;
const allWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
const allWidgetsFromRedux: CanvasWidgetsReduxState = yield select(getWidgets);
const allWidgets = klona(allWidgetsFromRedux) as CanvasWidgetsReduxState;
Copy link
Contributor Author

@jsartisan jsartisan Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@riodeuno Is this safe? The use case is aichatwidget wants to modify the parent zone's elevatedBackground to false. ( that code is written in aichatbot blueprint operation ).
So the problem I was facing is if there is an existing zone that is empty and I drop aichatwidget into it, I was not able to modify the zone elevated background, as the redux state was coming from immer reducer and it was immutable, due to which the property was readonly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsartisan This is a problem because we will quickly lose track of where the original values were updated. Ideally, we should let the functions return what needs to be updated, then in this function we should use something like produce from immer to update the appropriate paths.

I'm not a 100% sure of what is happening in this PR, so I can't provide an alternative. Could you elaborate in the description on "how" we're going about changing the zone's elevatedBackground property?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@riodeuno Updated the description. Let me know if you need more info.

@jsartisan jsartisan added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels Oct 23, 2024
@riodeuno
Copy link
Contributor

@jsartisan @KelvinOm

Note:
The approach for BlueprintOperations needs a review. The way it integrates with the system is not clean and has resulted in some hacks like the following:

  • Sagas are directly called from Blueprint, causing it to be coupled with Datasource system.
  • Immutable data from widgets is cloned to be updated by Blueprint, resulting in mutation functions. (Not very functional and testable)

I'd suggest we unblock AI Chat with the changes in this PR, and revisit the system to understand how to modularise this particular service.

@jsartisan jsartisan merged commit 85226f4 into release Oct 25, 2024
235 of 241 checks passed
@jsartisan jsartisan deleted the chore/fix-blueprint-operation-anvil branch October 25, 2024 11:24
github-actions bot pushed a commit to Zeral-Zhang/appsmith that referenced this pull request Nov 20, 2024
)

In anvil, when widgets are dropped on canvas, we create a zone which has
`visual separation` marked as true by default.
Now, There is a usecase for the chat widget in which we want to modify
the zone`s `Visual separation` to false on creation of zone.

The code for bleuprint operation for chat widget would like this:

```js
blueprint: {
    operations: [
      {
        type: BlueprintOperationTypes.MODIFY_PROPS,
        fn: (
          widget: FlattenedWidgetProps,
          widgets: CanvasWidgetsReduxState,
          parent: FlattenedWidgetProps,
          layoutSystemType: LayoutSystemTypes,
        ) => {
          if (layoutSystemType !== LayoutSystemTypes.ANVIL) return [];

          const updates: UpdatePropertyArgs[] = [];
          const parentId = widget.parentId;

          if (!parentId) return updates;

          const parentWidget = widgets[parentId];

          // we want to proceed only if the parent is a zone widget and has no children
          if (
            parentWidget.children?.length === 0 &&
            parentWidget.type === "ZONE_WIDGET"
          ) {
            updates.push({
              widgetId: parentId,
              propertyName: "elevatedBackground",
              propertyValue: false,
            });
          }

          return updates;
        },
      },
    ],
  },
  ```

This should work fine, but in the code where we create zone and attaching widgets to it, after running the blueprint operations, we were not using the correct updated zone that returned from blueprint operations of the child widgets. This PR uses the correct zone.

Also there is a case where blueprint operation is not able to update the existing widgets because all properties of existing widgets were readonly. So cloned the widgets from redux before passing to widget addition saga functions.

/ok-to-test tags="@tag.All"

## Summary by CodeRabbit

- **New Features**
	- Improved clarity in widget handling by renaming parameters related to dragged widgets.
	- Streamlined the process of adding widgets to zones by simplifying parameter structures.

- **Bug Fixes**
	- Enhanced immutability in widget property updates within the state management process.

- **Style**
	- Updated CSS styles for the `.markdown` class, removing unnecessary pseudo-elements for improved formatting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/11474751370>
> Commit: 8a385ee
> <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11474751370&attempt=3" target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Wed, 23 Oct 2024 09:47:24 UTC
<!-- end of auto-generated comment: Cypress test results  -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
	- Improved clarity in widget handling by renaming parameters related to dragged widgets.
	- Enhanced functionality for adding widgets to zones by simplifying the data structure used.
	- Implemented safer state manipulation for widget addition using a deep copy approach.

- **Bug Fixes**
	- Addressed potential issues with direct state mutation during widget addition.

- **Style**
	- Updated CSS styles for the Markdown component by removing unnecessary pseudo-elements.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ok-to-test Required label for CI skip-changelog Adding this label to a PR prevents it from being listed in the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants