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: generateDataTreeWidget Fix #37172

Closed
wants to merge 5 commits into from
Closed

chore: generateDataTreeWidget Fix #37172

wants to merge 5 commits into from

Conversation

vsvamsi1
Copy link
Contributor

@vsvamsi1 vsvamsi1 commented Oct 31, 2024

Description

Tip

Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team).

Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR.

Fixes #Issue Number
or
Fixes Issue URL

Warning

If no issue exists, please create an issue first, and check with the maintainers if the issue is valid.

Automation

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

🔍 Cypress test results

Caution

🔴 🔴 🔴 Some tests have failed.
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/11612013649
Commit: a247e1f
Cypress dashboard.
Tags: @tag.All
Spec:
The following are new failures, please fix them before merging the PR:

  1. cypress/e2e/Regression/ClientSide/Autocomplete/Autocomplete_setters_spec.ts
  2. cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts
  3. cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSuggestion_spec.ts
  4. cypress/e2e/Regression/ClientSide/BugTests/InputTruncateCheck_Spec.ts
  5. cypress/e2e/Regression/ClientSide/OtherUIFeatures/ErrorMessages_spec.ts
  6. cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInputDynamicCurrencyCode_spec.js
  7. cypress/e2e/Regression/ClientSide/Widgets/Datepicker/DatePicker2_spec.js
  8. cypress/e2e/Regression/ClientSide/Widgets/PhoneInput/PhoneInputDynamicValue_spec.js
  9. cypress/e2e/Regression/ClientSide/Widgets/TableV2/table_data_change_spec.ts
  10. cypress/e2e/Regression/ServerSide/JsFunctionExecution/PlatformFn_spec.ts
List of identified flaky tests.
Thu, 31 Oct 2024 17:56:22 UTC

Communication

Should the DevRel and Marketing teams inform users about this change?

  • Yes
  • No

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced new static methods in the DataTreeFactory for enhanced data tree generation: metaWidgets, widgets, and actions.
    • Added several new selector functions for improved data retrieval and organization, including getActionsFromUnevaluatedTree and getWidgetsFromUnevaluatedTree.
  • Improvements

    • Streamlined logic in existing selector functions for better clarity and maintainability.
    • Enhanced performance in the getAllPathsFromPropertyConfig function with memoization.
    • Updated test cases to reflect changes in widget generation logic, improving specificity in expected outputs.
  • Bug Fixes

    • Improved state management in the loadingEntitiesReducer to prevent unnecessary updates.

@vsvamsi1 vsvamsi1 requested a review from rajatagrawal October 31, 2024 11:39
Copy link
Contributor

coderabbitai bot commented Oct 31, 2024

Walkthrough

The changes in this pull request involve a significant refactoring of the DataTreeFactory class in dataTreeFactory.ts, where the create method is replaced by three new static methods: metaWidgets, widgets, and actions, each designed for specific data tree generation tasks. Additionally, modifications are made to the dataTreeWidget.ts, utils.ts, loadingEntitiesReducer.ts, and dataTreeSelectors.ts files, enhancing functionality, performance, and clarity across various components.

Changes

File Path Change Summary
app/client/src/entities/DataTree/dataTreeFactory.ts - Removed create method.
- Added metaWidgets, widgets, and actions methods with specific parameters for data tree generation.
- Introduced spans for telemetry and updated imports.
app/client/src/entities/DataTree/dataTreeWidget.ts - Updated generateDataTreeWidgetWithoutMeta to accept pureWidget and utilize omit for property filtering.
- Maintained memoization for performance.
app/client/src/entities/Widget/utils.ts - Updated getAllPathsFromPropertyConfig to include memoization with a maxSize of 1000.
app/client/src/reducers/evaluationReducers/loadingEntitiesReducer.ts - Modified loadingEntitiesReducer to check for equality before updating state on SET_LOADING_ENTITIES action to prevent unnecessary state changes.
app/client/src/selectors/dataTreeSelectors.ts - Renamed getCurrentActionEntities to getCurrentActionsEntities.
- Refactored getUnevaluatedDataTree into multiple selectors for better organization and clarity.
- Updated imports to include new types.

Possibly related PRs

  • chore: Add evalTreeWithDiff to evalWorkerAction #34403: The changes in this PR involve modifications to the DataTreeEvaluator and related functions, which may interact with the DataTreeFactory class in the main PR by affecting how data trees are evaluated and updated.
  • fix(#16584): filterTableData source of truth #36849: This PR enhances the getFilteredTableData function, which is relevant to the DataTreeFactory as it deals with data manipulation and filtering, potentially impacting how data trees are generated and displayed.
  • fix: Refactor handling of empty chart data in ChartWidget #37009: The modifications to the emptyChartData function in the ChartWidget component may relate to the changes in the main PR as they both involve handling data structures and ensuring proper data representation in the UI.
  • chore: Create query selector #37018: The updates to the createTempDatasourceFromForm function and the introduction of a new dropdown variant may connect with the main PR's focus on data handling and widget configuration, particularly in how data sources are managed within the application.

Suggested labels

Bug, Enhancement, Task, Widgets Product, Query & JS Pod, ok-to-test, Table Widget V2, Chart Widget, Datasources

Suggested reviewers

  • ApekshaBhosale
  • rahulbarwal
  • jsartisan
  • sagar-qa007

🎉 In the land of code, a change took flight,
DataTreeFactory shines, oh what a sight!
With methods anew, clarity reigns,
Widgets and actions dance in their lanes.
Performance enhanced, and logic refined,
In the world of devs, harmony we find! 🌟


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d4466ed and a247e1f.

📒 Files selected for processing (1)
  • app/client/src/entities/DataTree/dataTreeWidget.test.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • app/client/src/entities/DataTree/dataTreeWidget.test.ts

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.

@vsvamsi1 vsvamsi1 changed the title Release14 chore: generateDataTreeWidget Fix Oct 31, 2024
@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 31, 2024
Copy link

⚠️ Cyclic Dependency Check:

This PR has increased the number of cyclic dependencies by 4, when compared with the release branch.

Refer this document to identify the cyclic dependencies introduced by this PR.

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: 2

🧹 Outside diff range and nitpick comments (3)
app/client/src/entities/DataTree/dataTreeWidget.ts (2)

Line range hint 134-137: Consider enhancing error handling in getSetterConfig

Currently, errors are only logged and swallowed. Consider propagating critical errors to allow proper error handling by the caller, especially for configuration-related issues that could affect widget functionality.

 } catch (e) {
-  error("Error while generating setter config", e);
+  error("Error while generating setter config:", e);
+  throw new Error(`Failed to generate setter config: ${e.message}`);
 }

Memoization cache size needs to be increased

The current memoization size of 1000 is insufficient as there are 2138 widget instances in the codebase. This could lead to cache invalidation and performance degradation.

  • Consider increasing the memoization cache size to at least 2500 to accommodate the current widget count with room for growth
  • Update the TODO comment with the actual widget count analysis
🔗 Analysis chain

Line range hint 337-343: Verify memoization cache size based on widget count

The fixed memoization size of 1000 might need adjustment. As noted in the TODO comment, this should be dynamic based on the number of widgets to prevent cache invalidation issues in larger applications.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Count the number of widget instances to determine if memoization size is sufficient
echo "Analyzing widget usage..."
rg -g "*.{ts,tsx}" -l "widgetId:" | xargs cat | grep -c "widgetId:" || echo "0"

Length of output: 131

app/client/src/entities/DataTree/dataTreeFactory.ts (1)

Line range hint 86-128: Simplify boolean checks by removing redundant !! operators

The double negation !! is unnecessary in the conditionals. Simplifying them enhances code readability.

Apply this diff:

- if (!!configEntity && !!unEvalEntity) {
+ if (configEntity && unEvalEntity) {
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ee02c0f and d4466ed.

📒 Files selected for processing (5)
  • app/client/src/entities/DataTree/dataTreeFactory.ts (2 hunks)
  • app/client/src/entities/DataTree/dataTreeWidget.ts (3 hunks)
  • app/client/src/entities/Widget/utils.ts (1 hunks)
  • app/client/src/reducers/evaluationReducers/loadingEntitiesReducer.ts (2 hunks)
  • app/client/src/selectors/dataTreeSelectors.ts (4 hunks)
🔇 Additional comments (12)
app/client/src/reducers/evaluationReducers/loadingEntitiesReducer.ts (2)

4-4: LGTM: Good choice using lodash's isEqual.

The addition of lodash's isEqual is appropriate for deep comparison of Set objects.


14-23: Performance optimization looks good, but verify the impact.

The optimization to prevent unnecessary state updates is well-implemented. The comment about Set complexity is helpful.

Let's verify the usage of this reducer and potential impact:

✅ Verification successful

Performance optimization is correctly implemented and safe to use

The optimization is well-justified as loadingEntities is used in critical UI rendering paths:

  • Used in widget tree building for determining loading states
  • Accessed via selectors for widget rendering decisions
  • Integrated with Redux state management properly

The isEqual check prevents unnecessary re-renders in the widget tree, which is valuable given the frequent state updates in the loading entities reducer.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for components that might be affected by this optimization
rg -l "loadingEntities" --type ts

# Look for potential performance tests
rg -l "loadingEntitiesReducer.*test" --type ts

Length of output: 618


Script:

#!/bin/bash
# Let's check the usage of loadingEntities in the reducer and its integration
ast-grep --pattern 'const loadingEntitiesReducer = createReducer<LoadingEntitiesState, ReduxAction<$_>>($_)'

# Check how loadingEntities is used in components
rg "loadingEntities" -A 5 -B 5 app/client/src/utils/widgetRenderUtils.tsx app/client/src/selectors/dataTreeSelectors.ts

# Check the state shape and integration
ast-grep --pattern 'interface LoadingEntitiesState {
  $$$
}'

Length of output: 9384

app/client/src/entities/DataTree/dataTreeWidget.ts (2)

2-2: LGTM: Import changes align with new functionality

The addition of omit from lodash and WIDGET_PROPS_TO_SKIP_FROM_EVAL constant supports the new widget property filtering mechanism.

Also applies to: 24-24


180-190: LGTM: Improved parameter naming and widget property filtering

The renaming from widget to pureWidget better indicates the unmodified nature of the input. The filtering of evaluation-specific properties using WIDGET_PROPS_TO_SKIP_FROM_EVAL is properly implemented.

app/client/src/entities/Widget/utils.ts (1)

370-370: Verify the memoization cache size limit.

The addition of a maxSize limit of 1000 entries for memoization could impact performance if there are widgets with many unique property configurations. Consider monitoring cache hit rates in production to validate this limit.

✅ Verification successful

Based on the analysis of the codebase:

  1. The getAllPathsFromPropertyConfig function is used extensively across different widget types (Table, Chart, Form, etc.) to process widget configurations
  2. The function is used in critical paths like widget operations, data tree evaluation, and migrations
  3. The memoization with maxSize 1000 appears in multiple places, suggesting it's a common pattern
  4. The function is used to process property paths, binding paths, validation paths, and trigger paths

The memoization cache size of 1000 is appropriate.

The limit of 1000 entries is reasonable because:

  • It's used consistently across similar memoized functions in the codebase
  • Widget configurations are typically finite and reused
  • The cache size provides a good balance between memory usage and performance
  • The function is called frequently during widget operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for the number of unique widget configurations to validate cache size

# Test: Search for widget property configurations
rg -l "propertyPaneConfig" | xargs -I {} ast-grep --pattern 'export const propertyPaneConfig = {
  $$$
}'

# Test: Check for widget types to estimate configuration variety
rg -o 'type: "[^"]*"' | sort | uniq -c

Length of output: 107


Script:

#!/bin/bash
# Let's try a different approach to analyze widget configurations and property paths

# Check for widget configuration patterns and their complexity
rg -A 5 "getAllPathsFromPropertyConfig" 

# Look for property configuration patterns
rg -A 5 "propertyConfig" 

# Search for actual usage of the memoized function
rg -B 2 -A 2 "getAllPathsFromPropertyConfig\("

# Check for any existing memoization patterns
rg "memoize.*maxSize"

Length of output: 91222


Script:

#!/bin/bash
# Let's analyze the usage patterns and complexity of getAllPathsFromPropertyConfig

# Check implementation details of the function
ast-grep --pattern 'const getAllPathsFromPropertyConfigWithoutMemo = (
  $$$
) {
  $$$
}'

# Look for similar memoization patterns in the codebase
rg "memoize.*\{.*maxSize" -A 1

# Check test coverage for this function
rg -A 10 "describe.*getAllPathsFromPropertyConfig"

Length of output: 59010


Script:

#!/bin/bash
# Let's analyze the usage and complexity of the function to validate the cache size

# Look for widget property configurations to understand potential unique combinations
rg -l "propertyPaneConfig" --type ts

# Check for widget types and their configurations
rg "type:\s+['\"].*['\"]" --type ts

# Look for the actual implementation to understand memory usage
ast-grep --pattern 'const getAllPathsFromPropertyConfigWithoutMemo = (
  $_
) {
  $$$
}'

Length of output: 329319

app/client/src/entities/DataTree/dataTreeFactory.ts (3)

28-54: LGTM

The static metaWidgets method is structured appropriately and the implementation is clear.


56-84: LGTM

The static widgets method effectively handles widget data tree generation with clear parameter usage.


130-151: LGTM

The static jsActions method correctly processes JS actions with appropriate use of reduction.

app/client/src/selectors/dataTreeSelectors.ts (4)

72-81: Ensure all references to 'getCurrentJSActionsEntities' are updated

The function getCurrentJSActionsEntities consolidates JS actions correctly. Confirm that all instances of the old function name are replaced to avoid any unresolved references.

Run the following script to locate outdated references:

#!/bin/bash
# Description: Search for any remaining usages of the old function name.
rg 'getCurrentJSActionEntities'

137-158: ⚠️ Potential issue

Update function reference in 'getWidgetsFromUnevaluatedTree'

The selector getWidgetsFromUnevaluatedTree should reference the corrected function name.

Apply this diff to update the function reference:

-  getModuleComponentsFromUnEvaluatedTree,
+  getModuleComponentsFromUnevaluatedTree,

Likely invalid or redundant comment.


121-134: ⚠️ Potential issue

Correct the capitalization in 'getModuleComponentsFromUnEvaluatedTree'

The function name getModuleComponentsFromUnEvaluatedTree has inconsistent capitalization in 'Unevaluated'. Rename it to getModuleComponentsFromUnevaluatedTree for consistency.

Apply this diff to correct the function name:

-const getModuleComponentsFromUnEvaluatedTree = createSelector(
+const getModuleComponentsFromUnevaluatedTree = createSelector(

Ensure all references are updated accordingly.

Run the following script to find and replace the incorrect function name:


62-71: Verify consistency in function naming for 'getCurrentActionsEntities'

The function name has been updated to getCurrentActionsEntities. Please ensure all references to the previous getCurrentActionEntities are updated to maintain consistency and prevent potential errors.

Run the following script to check for any remaining references:

Comment on lines +153 to +180
public static actions(
actions: ActionDataState,
editorConfigs: Record<string, unknown[]>,
pluginDependencyConfig: Record<string, DependencyMap>,
) {
const actionsSpan = startRootSpan("DataTreeFactory.actions");

const res = actions.reduce(
(acc, action) => {
const editorConfig = editorConfigs[action.config.pluginId];
const dependencyConfig = pluginDependencyConfig[action.config.pluginId];
const { configEntity, unEvalEntity } = generateDataTreeAction(
action,
editorConfig,
dependencyConfig,
);

const end = performance.now();
acc.dataTree[action.config.name] = unEvalEntity;
acc.configTree[action.config.name] = configEntity;

const out = {
total: end - start,
widgets: endWidgets - startWidgets,
actions: endActions - startActions,
jsActions: endJsActions - startJsActions,
metaWidgets: endMetaWidgets - startMetaWidgets,
};
return acc;
},
{ dataTree: {} as UnEvalTree, configTree: {} as ConfigTree },
);

log.debug("### Create unevalTree timing", out);
endSpan(actionsSpan);

return { unEvalTree: dataTree, configTree };
return res;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure safe access to editorConfig and dependencyConfig

If editorConfigs or pluginDependencyConfig do not contain the pluginId, accessing them may result in undefined. Consider providing default values to prevent potential runtime errors.

Apply this diff to add default values:

 const editorConfig = editorConfigs[action.config.pluginId] || [];
 const dependencyConfig = pluginDependencyConfig[action.config.pluginId] || {};
 const { configEntity, unEvalEntity } = generateDataTreeAction(
   action,
   editorConfig,
   dependencyConfig,
 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static actions(
actions: ActionDataState,
editorConfigs: Record<string, unknown[]>,
pluginDependencyConfig: Record<string, DependencyMap>,
) {
const actionsSpan = startRootSpan("DataTreeFactory.actions");
const res = actions.reduce(
(acc, action) => {
const editorConfig = editorConfigs[action.config.pluginId];
const dependencyConfig = pluginDependencyConfig[action.config.pluginId];
const { configEntity, unEvalEntity } = generateDataTreeAction(
action,
editorConfig,
dependencyConfig,
);
const end = performance.now();
acc.dataTree[action.config.name] = unEvalEntity;
acc.configTree[action.config.name] = configEntity;
const out = {
total: end - start,
widgets: endWidgets - startWidgets,
actions: endActions - startActions,
jsActions: endJsActions - startJsActions,
metaWidgets: endMetaWidgets - startMetaWidgets,
};
return acc;
},
{ dataTree: {} as UnEvalTree, configTree: {} as ConfigTree },
);
log.debug("### Create unevalTree timing", out);
endSpan(actionsSpan);
return { unEvalTree: dataTree, configTree };
return res;
public static actions(
actions: ActionDataState,
editorConfigs: Record<string, unknown[]>,
pluginDependencyConfig: Record<string, DependencyMap>,
) {
const actionsSpan = startRootSpan("DataTreeFactory.actions");
const res = actions.reduce(
(acc, action) => {
const editorConfig = editorConfigs[action.config.pluginId] || [];
const dependencyConfig = pluginDependencyConfig[action.config.pluginId] || {};
const { configEntity, unEvalEntity } = generateDataTreeAction(
action,
editorConfig,
dependencyConfig,
);
acc.dataTree[action.config.name] = unEvalEntity;
acc.configTree[action.config.name] = configEntity;
return acc;
},
{ dataTree: {} as UnEvalTree, configTree: {} as ConfigTree },
);
endSpan(actionsSpan);
return res;

Comment on lines +183 to +214
let dataTree: UnEvalTree = {};
let configTree: ConfigTree = {};
const rootSpan = startRootSpan("DataTreeFactory.create");

configTree = {
...actions.configTree,
...jsActions.configTree,
...widgets.configTree,
};
dataTree = {
...actions.dataTree,
...jsActions.dataTree,
...widgets.dataTree,
};

dataTree.appsmith = {
...appData,
// combine both persistent and transient state with the transient state
// taking precedence in case the key is the same
store: appData.store,
theme,
} as AppsmithEntity;
configTree = { ...configTree, ...metaWidgets.configTree };
dataTree = { ...dataTree, ...metaWidgets.dataTree };

endSpan(rootSpan);

return {
configTree,
unEvalTree: dataTree,
};
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize data tree merging for better readability

The merging of configTree and dataTree uses multiple spread operators. Consider refactoring this logic into utility functions to enhance readability and maintainability.

Copy link

⚠️ Cyclic Dependency Check:

This PR has increased the number of cyclic dependencies by 4, when compared with the release branch.

Refer this document to identify the cyclic dependencies introduced by this PR.

@vsvamsi1 vsvamsi1 added the ok-to-test Required label for CI label Oct 31, 2024
@vsvamsi1 vsvamsi1 closed this Nov 4, 2024
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.

1 participant