Skip to content

Conversation

@saharAdem
Copy link

@saharAdem saharAdem commented Sep 10, 2025

Description

This PR resolves MultiSelect widgets issue, where MultiSelect widgets inside a ListWidget lose their selected values when switching between list items. The fix ensures that selected values are persisted per list item, maintaining user selections as they navigate through the list

Fixes #41210

Automation

/ok-to-test tags=""

🔍 Cypress test results

Caution

If you modify the content in this section, you are likely to disrupt the CI result for your PR.

Communication

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

  • Yes
  • No

Summary by CodeRabbit

  • New Features

    • Widgets now track and persist selections per list item and expose a per-item identifier and current-item context for item-scoped state.
  • Bug Fixes

    • Multi-select inside lists maintains correct selections when switching, deleting, or reindexing items; selection maps stay synchronized with item order.
  • Tests

    • Added end-to-end tests validating per-item selection persistence across focus, preview, deletion, and index changes.

✏️ Tip: You can customize this high-level summary in your review settings.

@saharAdem saharAdem requested a review from a team as a code owner September 10, 2025 08:44
@saharAdem saharAdem requested review from vivek-appsmith and removed request for a team September 10, 2025 08:44
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Walkthrough

Adds per-list-item persistence for MultiSelectWidgetV2 via a new meta-map keyed by list item id/currentIndex, synchronizes that map when indices change or items are deleted, exposes per-item listItemId on ListWidgetV2 meta-widgets, and adds a Cypress regression spec validating persistence.

Changes

Cohort / File(s) Summary of changes
MultiSelect — per-item selection state
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx
Introduces selectedValuesByItem meta-map and currentIndex? prop; reads/writes per-item selection arrays at selectedValuesByItem[itemId]; replaces global selectedOptions path with per-item persistence via updateWidgetMetaProperty; adds syncSelectionMapOnIndexChange, getListItemId, and adjusts mergeLabelAndValue/lifecycle logic; updates getMetaPropertiesMap() to include selectedValuesByItem.
ListWidget — expose item id on meta
app/client/src/widgets/ListWidgetV2/widget/index.tsx
Adds optional listItemId?: string to BaseMetaWidget; in afterMetaWidgetGenerate, sets metaWidget.listItemId from metaWidgetGenerator.getPrimaryKey(currentIndex) when currentIndex >= 0.
E2E regression test
app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
New Cypress spec verifying per-item MultiSelect persistence across item focus and deletion; includes helpers for widget selectors and assertions on persisted values after interactions.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant L as ListWidgetV2
  participant M as MultiSelectWidgetV2
  participant S as MetaStore (selectedValuesByItem)

  U->>L: Focus item i
  L->>M: Render with currentIndex = i (and listItemId)
  M->>S: Read selectedValuesByItem[listItemId]
  alt missing entry
    M->>S: updateWidgetMetaProperty(selectedValuesByItem[listItemId] = defaultOptionValue)
  end
  M-->>U: Display per-item values

  U->>M: Change selection -> newValues
  M->>S: updateWidgetMetaProperty(selectedValuesByItem[listItemId] = newValues)

  U->>L: Focus item j or delete item k
  L->>M: Render with currentIndex = j
  M->>S: syncSelectionMapOnIndexChange(...) -> remap/shift keys as needed
  M->>S: Read selectedValuesByItem[newListItemId]
  M-->>U: Display values for item j
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review focus areas:
    • Correctness and edge cases in syncSelectionMapOnIndexChange (remapping, shifting on deletions).
    • Consistency between getListItemId, currentIndex, and listItemId supplied by ListWidgetV2.
    • Shape and atomicity of selectedValuesByItem persisted via updateWidgetMetaProperty.
    • Changes in mergeLabelAndValue to ensure displayed values match persisted format.
    • Cypress spec robustness: selectors, timing, and assumptions about list length/indexing.

Poem

Little maps that hold each hue,
Keys for items, old and new;
When indexes shift or items part,
Selections kept, safe in heart,
Red and green stay true. 🎉

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: fixing MultiSelect widget selected values persistence inside a List widget.
Description check ✅ Passed The description follows the template structure, includes issue reference (#41210), explains the problem and solution, and includes required automation and communication sections.
Linked Issues check ✅ Passed Code changes implement per-item selection tracking via selectedValuesByItem map and listItemId propagation, directly addressing issue #41210's core requirement to persist MultiSelect selections per list item.
Out of Scope Changes check ✅ Passed All changes align with the linked issue #41210: MultiSelectWidgetV2 modifications add per-item persistence logic, ListWidgetV2 adds listItemId support, and the Cypress test validates the bug fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

🧹 Nitpick comments (2)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (2)

849-850: Redundant type assertion can be removed

Since defaultOptionValue is already typed as string[] | OptionValue[] in the props, the explicit type assertion to string[] on line 850 is unnecessary.

-      values = defaultOptionValue as string[];
+      values = defaultOptionValue;

906-924: Consider edge case handling for currentIndex

The implementation assumes currentIndex is always defined, but this might not be true for widgets outside of list contexts. Consider adding a fallback.

   onOptionChange = (value: DraftValueType) => {
-    const itemId = this.props.currentIndex;
+    const itemId = this.props.currentIndex ?? "default";
     const updatedValue = {
       ...(this.props.selectedValuesByItem || {}),
       [itemId]: value,
     };
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1401ea and a55fd9b.

📒 Files selected for processing (2)
  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts (1 hunks)
  • app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/client/cypress/**/**.*

⚙️ CodeRabbit configuration file

app/client/cypress/**/**.*: Review the following e2e test code written using the Cypress test library. Ensure that:

  • Follow best practices for Cypress code and e2e automation.
  • Avoid using cy.wait in code.
  • Avoid using cy.pause in code.
  • Avoid using agHelper.sleep().
  • Use locator variables for locators and do not use plain strings.
  • Use data-* attributes for selectors.
  • Avoid Xpaths, Attributes and CSS path.
  • Avoid selectors like .btn.submit or button[type=submit].
  • Perform logins via API with LoginFromAPI.
  • Perform logout via API with LogOutviaAPI.
  • Perform signup via API with SignupFromAPI.
  • Avoid using it.only.
  • Avoid using after and aftereach in test cases.
  • Use multiple assertions for expect statements.
  • Avoid using strings for assertions.
  • Do not use duplicate filenames even with different paths.
  • Avoid using agHelper.Sleep, this.Sleep in any file in code.

Files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: vhemery
PR: appsmithorg/appsmith#37371
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js:35-37
Timestamp: 2024-11-13T09:11:36.959Z
Learning: In the file `app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js`, when writing Cypress end-to-end tests for the Image Widget in JavaScript, use `viewWidgetsPage.imageinner` as the selector when asserting 'src' and 'alt' attributes to maintain consistency.
📚 Learning: 2024-11-13T09:11:36.959Z
Learnt from: vhemery
PR: appsmithorg/appsmith#37371
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js:35-37
Timestamp: 2024-11-13T09:11:36.959Z
Learning: In the file `app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js`, when writing Cypress end-to-end tests for the Image Widget in JavaScript, use `viewWidgetsPage.imageinner` as the selector when asserting 'src' and 'alt' attributes to maintain consistency.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: abhishek-bandameedi
PR: appsmithorg/appsmith#35133
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBox2_spec.js:0-0
Timestamp: 2024-10-08T15:32:34.115Z
Learning: In Cypress tests for the Appsmith project, ensure the use of locator variables for selectors and include multiple assertions for comprehensive testing.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts
🔇 Additional comments (1)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (1)

839-856: Good implementation of per-item selection persistence

The logic correctly tracks selections per list item using currentIndex as the key and properly initializes with default values when an item hasn't been accessed before.

Comment on lines 1 to 28
import { locators } from "../../../../support/Objects/ObjectsCore";
import * as _ from "../../../../support/Objects/ObjectsCore";

const widgetSelector = (name: string) => `[data-widgetname-cy="${name}"]`;

describe("Bug 41210: MultiSelectWidgetV2 inside ListWidget - selected values and labels persist per item", function () {
before(() => {
_.agHelper.AddDsl("Listv2/emptyList");
});

it("should persist selected values for each list item and initialize with default values on first render", function () {
cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", {
x: 250,
y: 50,
});
_.propPane.UpdatePropertyFieldValue("Default selected values", '["GREEN"]');
_.agHelper.GetNClick(locators._enterPreviewMode);
_.agHelper.SelectFromMultiSelect(["Red"]);

const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;

cy.get(listContainer).eq(1).click();
cy.get(listContainer).eq(0).click();
cy.get(
`${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
).should("contain.text", "Red");
});
});
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

Fix the filename to follow naming conventions

The filename contains a space between "Bug" and "41210" which violates standard naming conventions. Rename the file to use underscores or camelCase consistently.

-MultiselectWidget_Bug 41210 _Spec.ts
+MultiselectWidget_Bug41210_Spec.ts

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug
41210 _Spec.ts lines 1-28: the filename contains a space ("Bug 41210") which
violates repo naming conventions; rename the file to remove spaces (e.g.,
MultiselectWidget_Bug_41210_Spec.ts or multiselectWidgetBug41210Spec.ts) using
git mv, update any CI/test references or import paths that point to the old
filename, and ensure the test runner configuration or any documentation is
updated accordingly so the test still runs under the new name.

Comment on lines 11 to 27
it("should persist selected values for each list item and initialize with default values on first render", function () {
cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", {
x: 250,
y: 50,
});
_.propPane.UpdatePropertyFieldValue("Default selected values", '["GREEN"]');
_.agHelper.GetNClick(locators._enterPreviewMode);
_.agHelper.SelectFromMultiSelect(["Red"]);

const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;

cy.get(listContainer).eq(1).click();
cy.get(listContainer).eq(0).click();
cy.get(
`${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
).should("contain.text", "Red");
});
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

Test lacks comprehensive assertions

The test only verifies that "Red" is selected but doesn't verify:

  1. That the default value "GREEN" was initially selected
  2. That other list items maintain their own selections
  3. That the selection persists after multiple navigations
   it("should persist selected values for each list item and initialize with default values on first render", function () {
     cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", {
       x: 250,
       y: 50,
     });
     _.propPane.UpdatePropertyFieldValue("Default selected values", '["GREEN"]');
     _.agHelper.GetNClick(locators._enterPreviewMode);
+    
+    // Verify default value is selected
+    cy.get(
+      `${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
+    ).should("contain.text", "Green");
+    
     _.agHelper.SelectFromMultiSelect(["Red"]);
 
     const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;
 
+    // Navigate to second item and verify it has the default value
     cy.get(listContainer).eq(1).click();
+    cy.get(
+      `${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
+    ).should("contain.text", "Green");
+    
+    // Return to first item and verify Red persists
     cy.get(listContainer).eq(0).click();
     cy.get(
       `${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
     ).should("contain.text", "Red");
+    
+    // Navigate again to ensure persistence
+    cy.get(listContainer).eq(1).click();
+    cy.get(listContainer).eq(0).click();
+    cy.get(
+      `${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
+    ).should("contain.text", "Red");
   });
📝 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
it("should persist selected values for each list item and initialize with default values on first render", function () {
cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", {
x: 250,
y: 50,
});
_.propPane.UpdatePropertyFieldValue("Default selected values", '["GREEN"]');
_.agHelper.GetNClick(locators._enterPreviewMode);
_.agHelper.SelectFromMultiSelect(["Red"]);
const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;
cy.get(listContainer).eq(1).click();
cy.get(listContainer).eq(0).click();
cy.get(
`${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
).should("contain.text", "Red");
});
it("should persist selected values for each list item and initialize with default values on first render", function () {
cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", {
x: 250,
y: 50,
});
_.propPane.UpdatePropertyFieldValue("Default selected values", '["GREEN"]');
_.agHelper.GetNClick(locators._enterPreviewMode);
// Verify default value is selected
cy.get(
`${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
).should("contain.text", "Green");
_.agHelper.SelectFromMultiSelect(["Red"]);
const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;
// Navigate to second item and verify it has the default value
cy.get(listContainer).eq(1).click();
cy.get(
`${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
).should("contain.text", "Green");
// Return to first item and verify Red persists
cy.get(listContainer).eq(0).click();
cy.get(
`${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
).should("contain.text", "Red");
// Navigate again to ensure persistence
cy.get(listContainer).eq(1).click();
cy.get(listContainer).eq(0).click();
cy.get(
`${widgetSelector("MultiSelect1")} .rc-select-selection-item`,
).should("contain.text", "Red");
});
🤖 Prompt for AI Agents
app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug
41210 _Spec.ts lines 11-27: the test only asserts that "Red" is selected but
misses verifying the initial default "GREEN", per-item selection independence,
and persistence after navigation; update the test to first assert that on first
render MultiSelect1 contains "GREEN" (the default), then select a different
option for a second list item and assert that each list item shows its own
selected value (e.g., item0 shows "GREEN", item1 shows "Red"), then navigate
between list items (click other indices) multiple times and re-check the
selections to confirm persistence across navigations; use the same widget
selectors already present (widgetSelector("MultiSelect1") and listContainer
indices) and add assertions after each navigation step to validate the expected
text values.

Comment on lines 12 to 15
cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", {
x: 250,
y: 50,
});
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

Avoid using coordinate-based drag and drop

Using fixed x,y coordinates (250, 50) for drag and drop operations is brittle and may fail on different screen sizes or when the UI changes. Consider using a more robust approach.

#!/bin/bash
# Check if there are helper methods available for drag and drop operations without coordinates
rg -n --type=ts "dragAndDropToWidget.*widgetSelector" -A 3 -B 3
🤖 Prompt for AI Agents
In app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug
41210 _Spec.ts around lines 12 to 15, the test uses fixed x,y coordinates for
cy.dragAndDropToWidget which is brittle; update the call to use a selector-based
target (or the helper's widgetSelector option) so the drop is done relative to
the target element instead of absolute coordinates — either pass the destination
widget selector to cy.dragAndDropToWidget (remove the x/y object) or compute the
target's center via cy.get('<target-selector>').then(el => { use its bounding
box to perform the drag/drop }) so the test works across screen sizes and layout
changes.

_.agHelper.GetNClick(locators._enterPreviewMode);
_.agHelper.SelectFromMultiSelect(["Red"]);

const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;
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

Avoid using CSS attribute selectors

The selector [type="CONTAINER_WIDGET"] violates the coding guidelines which specify avoiding attribute selectors. Use data-* attributes instead.

-    const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;
+    const listContainer = `${widgetSelector("List1")} [data-testid="list-container"]`;

Note: Ensure the corresponding data-testid attribute is added to the container widget in the application code.

📝 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
const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`;
const listContainer = `${widgetSelector("List1")} [data-testid="list-container"]`;
🤖 Prompt for AI Agents
In app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug
41210 _Spec.ts around line 20, the selector uses a CSS attribute selector
`[type="CONTAINER_WIDGET"]` which violates guidelines; replace it with a
data-testid selector and update the application to add that data-testid to the
container widget. Change the test to target the container via its data-testid
(e.g., `${widgetSelector("List1")} [data-testid="container-widget-List1"]` or a
stable name you add in the app) and add the corresponding data-testid attribute
to the container widget in the app code.

@vivek-appsmith vivek-appsmith requested review from ankitakinger, jacquesikot and rahulbarwal and removed request for vivek-appsmith September 11, 2025 04:42
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (1)

774-780: Add selectedValuesByItem to the meta properties map.

selectedValuesByItem is read/updated (componentDidUpdate, onOptionChange) but missing from getMetaPropertiesMap; add selectedValuesByItem: {} to the return object in app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (around lines 774–780).

🧹 Nitpick comments (3)
app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (2)

2-2: Remove unnecessary wildcard import.

The wildcard import * as _ is not following best practices and is inconsistent with the specific locators import above it.

-import * as _ from "../../../../support/Objects/ObjectsCore";
+import { agHelper, propPane } from "../../../../support/Objects/ObjectsCore";

12-15: Use specific coordinates or consider alternatives to hardcoded positioning.

The hardcoded coordinates (x: 250, y: 50) may be brittle across different screen sizes or viewport configurations.

-    cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", {
-      x: 250,
-      y: 50,
-    });
+    cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget");
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (1)

991-1019: Add interface documentation for new properties.

The new currentIndex and selectedValuesByItem properties should be documented to clarify their purpose in the per-item persistence feature.

export interface MultiSelectWidgetProps extends WidgetProps {
  // ... existing properties ...
+ /** Current index of the list item when widget is inside a ListWidget */
+ currentIndex: number;
+ /** Map of selected values per list item, keyed by list item index */
+ selectedValuesByItem?: Record<string, string[] | OptionValue[]>;
  // ... remaining properties ...
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a55fd9b and 633558c.

📒 Files selected for processing (2)
  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (1 hunks)
  • app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/client/cypress/**/**.*

⚙️ CodeRabbit configuration file

app/client/cypress/**/**.*: Review the following e2e test code written using the Cypress test library. Ensure that:

  • Follow best practices for Cypress code and e2e automation.
  • Avoid using cy.wait in code.
  • Avoid using cy.pause in code.
  • Avoid using agHelper.sleep().
  • Use locator variables for locators and do not use plain strings.
  • Use data-* attributes for selectors.
  • Avoid Xpaths, Attributes and CSS path.
  • Avoid selectors like .btn.submit or button[type=submit].
  • Perform logins via API with LoginFromAPI.
  • Perform logout via API with LogOutviaAPI.
  • Perform signup via API with SignupFromAPI.
  • Avoid using it.only.
  • Avoid using after and aftereach in test cases.
  • Use multiple assertions for expect statements.
  • Avoid using strings for assertions.
  • Do not use duplicate filenames even with different paths.
  • Avoid using agHelper.Sleep, this.Sleep in any file in code.

Files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
🧠 Learnings (2)
📚 Learning: 2024-11-13T09:11:36.959Z
Learnt from: vhemery
PR: appsmithorg/appsmith#37371
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js:35-37
Timestamp: 2024-11-13T09:11:36.959Z
Learning: In the file `app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js`, when writing Cypress end-to-end tests for the Image Widget in JavaScript, use `viewWidgetsPage.imageinner` as the selector when asserting 'src' and 'alt' attributes to maintain consistency.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: abhishek-bandameedi
PR: appsmithorg/appsmith#35133
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBox2_spec.js:0-0
Timestamp: 2024-10-08T15:32:34.115Z
Learning: In Cypress tests for the Appsmith project, ensure the use of locator variables for selectors and include multiple assertions for comprehensive testing.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
🧬 Code graph analysis (1)
app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (1)
app/client/cypress/support/commands.js (2)
  • _ (1071-1071)
  • locators (43-43)
🔇 Additional comments (4)
app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (1)

16-26: LGTM! Test logic correctly validates per-item persistence.

The test properly validates the bug fix by:

  1. Setting a default value
  2. Selecting a different option in the first list item
  3. Switching focus between list items
  4. Verifying the selection persists in the original item

The use of data-widgetname-cy selectors and specific container targeting aligns with coding guidelines.

app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (3)

813-824: LGTM! Proper initialization of per-item state on default value changes.

The implementation correctly handles initialization of per-item selections when defaultOptionValue changes, ensuring each list item gets its own selection state.


902-920: LGTM! Per-item selection tracking implemented correctly.

The onOptionChange method properly stores selections per list item using currentIndex as the key, maintaining the existing trigger semantics while adding per-item persistence.


924-941: LGTM! Smart initialization of per-item defaults.

The mergeLabelAndValue method correctly:

  1. Retrieves per-item values or falls back to defaults
  2. Initializes missing per-item state with default values
  3. Returns the appropriate values for the current list item

This ensures each list item maintains its own selection state while preserving backward compatibility.

@github-actions
Copy link

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions bot added the Stale label Sep 18, 2025
@saharAdem
Copy link
Author

saharAdem commented Sep 19, 2025

@rahulbarwal @jacquesikot @ankitakinger Could you please review the PR?

@github-actions github-actions bot removed the Stale label Sep 19, 2025
@github-actions
Copy link

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions bot added the Stale label Sep 26, 2025
@saharAdem
Copy link
Author

Hey @Nikhil-Nandagopal, any updates on this?

@github-actions github-actions bot removed the Stale label Oct 1, 2025
@github-actions
Copy link

github-actions bot commented Oct 9, 2025

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions bot added the Stale label Oct 9, 2025
@saharAdem
Copy link
Author

Hey, any updates?

@github-actions github-actions bot removed the Stale label Oct 14, 2025
@github-actions
Copy link

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions bot added the Stale label Oct 21, 2025
@github-actions
Copy link

This PR has been closed because of inactivity.

@github-actions github-actions bot closed this Oct 28, 2025
@jacquesikot jacquesikot self-assigned this Nov 5, 2025
@jacquesikot
Copy link
Contributor

jacquesikot commented Nov 6, 2025

@saharAdem Please check these

Potential Issues & Recommendations

  1. Missing Interface Updates

The MultiSelectWidgetProps interface at the bottom of the file doesn't include the new props:

  // Missing in current interface:
  currentIndex?: number;
  selectedValuesByItem?: Record<string, DraftValueType>;

These should be added to app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx:197-225

  1. Meta Properties Map

getMetaPropertiesMap() at line 774 should include selectedValuesByItem:

  static getMetaPropertiesMap(): Record<string, any> {
    return {
      selectedOptions: undefined,
      filterText: "",
      isDirty: false,
      selectedValuesByItem: {}, // Add this
    };
  }
  1. Type Safety Concerns
  • currentIndex is used as both string and number - should be consistent
  • In PR: String(this.props.currentIndex) suggests it might be a number
  • Better to define: const itemId: string = String(currentIndex ?? 0)
  1. Edge Cases to Test
  • What happens when currentIndex is undefined?
  • Does it handle list item deletion/reordering correctly?
  • Memory leak concerns with growing selectedValuesByItem map if list items are dynamically added/removed
  1. Performance
  • Consider if selectedValuesByItem needs cleanup when list items are removed
  • Large lists with many items could accumulate stale data

Recommendations

  1. Add the missing interface properties
  2. Add selectedValuesByItem to meta properties map
  3. Add defensive null checks for currentIndex
  4. Test edge cases: list reordering, deletion, dynamic item count changes
  5. Consider cleanup logic for removed list items from selectedValuesByItem map

The approach is sound and well-designed for fixing the bug. The per-item state tracking is the right solution. However, there are some TypeScript interface completeness issues that should be addressed before merging to ensure type safety.

cc @rahulbarwal @ankitakinger

@jacquesikot jacquesikot reopened this Nov 6, 2025
@github-actions github-actions bot removed the Stale label Nov 6, 2025
@saharAdem
Copy link
Author

Thank you for your review @jacquesikot . I’ll be resolving your comments within the next two days.

@github-actions
Copy link

This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected.

@github-actions github-actions bot added the Stale label Nov 18, 2025
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 633558c and 16ae559.

📒 Files selected for processing (2)
  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (1 hunks)
  • app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
🔇 Additional comments (4)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (4)

779-779: Interface and meta properties look good.

The additions properly address the reviewer's concerns about missing properties. The types are appropriate for the per-item selection tracking functionality.

Also applies to: 1071-1072


961-979: Per-item selection storage looks correct.

The method properly stores selections keyed by currentIndex, preserves existing entries via spread, and maintains the isDirty flag. The fallback to 0 when currentIndex is undefined provides reasonable default behavior.


982-993: Value retrieval logic is clean and correct.

The fallback chain selectedValuesByItem[itemId] ?? defaultOptionValue ensures values are always available, and the destructuring with defaults prevents undefined errors.


833-884: <!-- [scratchpad_start]
[task verify_review_assumption 1/1]
[observations]

  • Review comment flags potential memory leak in MultiSelectWidgetV2
  • Claims selectedValuesByItem map accumulates entries indefinitely
  • Assumes List widget provides listSize property
  • Proposed fix adds cleanup logic in componentDidUpdate
  • Shell script output did not return the target file (tsx parsing error)
  • No verification of actual List widget API or accumulation pattern
    [analysis]
  • Review makes assumptions without confirming List widget exposes item count
  • Cleanup logic placement assumes componentDidUpdate executes on list resize
  • Without seeing actual usage patterns, cannot confirm if accumulation is real
  • The method shown (syncSelectionMapOnIndexChange) handles index shifts during navigation, not removal cleanup
    [pending]
  • Verify if List widget actually provides item count property
  • Confirm selectedValuesByItem actually grows unbounded in practice
  • Check if this is preventive or addressing observed issue
    [actions]
  • Request manual verification of List widget API
  • Ask developer to confirm observed memory growth
    [done]
    Unable to verify assumptions in review comment due to script failure and missing API visibility
    [scratchpad_end]

Verify assumptions about List widget API and actual memory accumulation.

The review assumes the List widget exposes an listSize property and that selectedValuesByItem grows unbounded in production. Without access to the List widget props interface or evidence of actual memory growth, these assumptions need confirmation.

Specifically verify:

  1. Does the List widget provide listSize, itemCount, or similar property?
  2. Is memory accumulation observed in practice, or is this preventive?
  3. Is componentDidUpdate always called when the list resizes?

If these assumptions don't hold, the proposed cleanup logic may be unnecessary or placed incorrectly.

@github-actions
Copy link

This PR has been closed because of inactivity.

@github-actions github-actions bot closed this Nov 26, 2025
@saharAdem saharAdem changed the title fix: Multiselect widget selected values inside list widget Fix: Multiselect widget selected values inside list widget Nov 26, 2025
@saharAdem
Copy link
Author

I’ve resolved the AI comments and added the list item ID for the list widget, but I can’t commit the changes because the PR is closed. Could you please reopen it? @jacquesikot

@alexgearing
Copy link

@jacquesikot Would it be possible to re-open this PR so we can submit the requested changes?

@vivek-appsmith vivek-appsmith reopened this Dec 2, 2025
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

♻️ Duplicate comments (1)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (1)

820-835: User selections may still be overwritten when defaultOptionValue changes.

Lines 820-823 reset isDirty to false when changes are detected, but lines 824-835 still unconditionally update selectedValuesByItem[listItemId] with the new defaultOptionValue. This overwrites user selections made for that item.

Consider guarding the update:

-    if (hasChanges) {
+    if (hasChanges && !this.props.isDirty) {
       const listItemId = this.getListItemId(this.props.currentIndex);

Or move the isDirty reset after the condition to preserve user selections when dirty.

🧹 Nitpick comments (3)
app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (3)

8-9: Prefer data-* attribute selectors over type attributes.

[type="CONTAINER_WIDGET"] is an attribute selector. Per coding guidelines, prefer data-* attributes for stability. If a data-testid or similar attribute exists on containers, use that instead.


53-55: CSS class selector from third-party component.

.rc-select-selection-item is a library-internal class. If a data-* attribute is available on these elements, prefer that for resilience against library updates. Otherwise, document this as a known fragile selector.


40-56: Consider adding baseline assertion before interaction.

Before selecting "Red", assert that the default "GREEN" is shown. This confirms the default value is applied correctly and makes test failures more diagnostic.

    _.agHelper.GetNClick(locators._enterPreviewMode);
+   cy.get(
+     `${locators._widgetByName("MultiSelect1")} .rc-select-selection-item`,
+   ).should("contain.text", "Green");
    _.agHelper.SelectFromMultiSelect(["Red"]);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16ae559 and 21fcf6d.

📒 Files selected for processing (3)
  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (1 hunks)
  • app/client/src/widgets/ListWidgetV2/widget/index.tsx (2 hunks)
  • app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/client/cypress/**/**.*

⚙️ CodeRabbit configuration file

app/client/cypress/**/**.*: Review the following e2e test code written using the Cypress test library. Ensure that:

  • Follow best practices for Cypress code and e2e automation.
  • Avoid using cy.wait in code.
  • Avoid using cy.pause in code.
  • Avoid using agHelper.sleep().
  • Use locator variables for locators and do not use plain strings.
  • Use data-* attributes for selectors.
  • Avoid Xpaths, Attributes and CSS path.
  • Avoid selectors like .btn.submit or button[type=submit].
  • Perform logins via API with LoginFromAPI.
  • Perform logout via API with LogOutviaAPI.
  • Perform signup via API with SignupFromAPI.
  • Avoid using it.only.
  • Avoid using after and aftereach in test cases.
  • Use multiple assertions for expect statements.
  • Avoid using strings for assertions.
  • Do not use duplicate filenames even with different paths.
  • Avoid using agHelper.Sleep, this.Sleep in any file in code.

Files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
🧠 Learnings (10)
📚 Learning: 2025-05-21T04:51:50.934Z
Learnt from: ashit-rath
Repo: appsmithorg/appsmith PR: 40711
File: app/client/src/widgets/ListWidgetV2/widget/index.tsx:514-532
Timestamp: 2025-05-21T04:51:50.934Z
Learning: In the ListWidgetV2 component, `klonaRegularWithTelemetry` is used to perform deep cloning of objects before modifying them, which is a valid pattern for preserving the original reference while making changes to a copy.

Applied to files:

  • app/client/src/widgets/ListWidgetV2/widget/index.tsx
📚 Learning: 2025-06-13T07:49:21.417Z
Learnt from: rahulbarwal
Repo: appsmithorg/appsmith PR: 40886
File: app/client/src/widgets/ListWidgetV2/MetaWidgetGenerator.ts:1115-1134
Timestamp: 2025-06-13T07:49:21.417Z
Learning: For ListWidgetV2, an empty array supplied by users is internally converted to `[{}]` (a placeholder row) when `pageNo === 1`; this sentinel is never produced by user data, so a singleton empty object on page 1 can be safely treated as “empty list” in MetaWidgetGenerator.

Applied to files:

  • app/client/src/widgets/ListWidgetV2/widget/index.tsx
📚 Learning: 2024-11-13T09:11:36.959Z
Learnt from: vhemery
Repo: appsmithorg/appsmith PR: 37371
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js:35-37
Timestamp: 2024-11-13T09:11:36.959Z
Learning: In the file `app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js`, when writing Cypress end-to-end tests for the Image Widget in JavaScript, use `viewWidgetsPage.imageinner` as the selector when asserting 'src' and 'alt' attributes to maintain consistency.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2025-11-05T12:56:49.249Z
Learnt from: vsvamsi1
Repo: appsmithorg/appsmith PR: 41363
File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts:0-0
Timestamp: 2025-11-05T12:56:49.249Z
Learning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 4-6 depend on state (`page1Slug`, `page2Slug`) set in Tests 2-3. The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2025-11-05T12:58:32.486Z
Learnt from: vsvamsi1
Repo: appsmithorg/appsmith PR: 41363
File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts:32-225
Timestamp: 2025-11-05T12:58:32.486Z
Learning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 2-5 depend on state from previous tests (e.g., slug values modified in earlier tests). The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: abhishek-bandameedi
Repo: appsmithorg/appsmith PR: 35133
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBox2_spec.js:0-0
Timestamp: 2024-10-08T15:32:34.115Z
Learning: In Cypress tests for the Appsmith project, ensure the use of locator variables for selectors and include multiple assertions for comprehensive testing.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: sagar-qa007
Repo: appsmithorg/appsmith PR: 34955
File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56
Timestamp: 2024-10-08T15:32:34.115Z
Learning: Learnt from: sagar-qa007
PR: appsmithorg/appsmith#34955
File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56
Timestamp: 2024-07-16T06:44:55.118Z
Learning: Avoid using sleep functions like `agHelper.Sleep`, `this.Sleep`, and other related sleep functions in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2024-07-26T21:12:57.228Z
Learnt from: Aishwarya-U-R
Repo: appsmithorg/appsmith PR: 29405
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Radio/Radio2_spec.ts:404-407
Timestamp: 2024-07-26T21:12:57.228Z
Learning: The `Radio2_spec.ts` file is not part of the initial phase for the removal of static waits in the pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1".

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2024-11-13T09:07:54.931Z
Learnt from: vhemery
Repo: appsmithorg/appsmith PR: 37371
File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js:44-47
Timestamp: 2024-11-13T09:07:54.931Z
Learning: When reviewing code in `app/client/cypress/**` paths, ensure that suggestions are appropriate for test code and not for `src` code. Avoid applying source code checks to test code unless relevant.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
📚 Learning: 2024-10-08T15:32:39.374Z
Learnt from: Aishwarya-U-R
Repo: appsmithorg/appsmith PR: 29405
File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41
Timestamp: 2024-10-08T15:32:39.374Z
Learning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.

Applied to files:

  • app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts
🧬 Code graph analysis (1)
app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (1)
app/client/cypress/support/commands.js (2)
  • _ (1071-1071)
  • locators (43-43)
🔇 Additional comments (9)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (5)

783-791: Solid implementation for stable item identification.

Using listItemId (stable primary key from List widget) over positional index prevents the mapping issues flagged in prior reviews. The fallback to String(index ?? 0) correctly handles standalone usage outside a List widget.


843-871: Clean per-item initialization logic.

This addresses the prior review feedback—no index-shifting, just on-demand initialization for missing entries. The reference equality check at line 868 avoids unnecessary meta property updates.


948-966: LGTM.

Correctly updates per-item state and marks the widget dirty on user interaction.


1058-1061: Interface additions look correct.

Optional properties maintain backward compatibility. Types align with their usage throughout the widget.


969-980: Verify type compatibility and function intent in mergeLabelAndValue.

The concern about type mismatch between the return type LabelInValueType[] and defaultOptionValue (potentially string[] | OptionValue[]) may be valid based on known patterns in Appsmith's MultiSelect handling, but this requires inspection of:

  • The actual type definition of defaultOptionValue at line 1040
  • How mergeLabelAndValue() is used across the codebase
  • Whether this is intentional fallback behavior or a latent bug

Additionally, verify if the function name mergeLabelAndValue still accurately describes its behavior as a simple getter.

app/client/src/widgets/ListWidgetV2/widget/index.tsx (2)

80-85: Clean type extension.

Adding listItemId to BaseMetaWidget enables per-item identity propagation to child widgets without breaking existing consumers.


728-736: Properly wires stable item identity.

Using getPrimaryKey for listItemId ensures child widgets (like MultiSelect) can key their per-item state to stable identifiers rather than volatile indices.

app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts (2)

11-38: Test setup is well-structured.

The JSObject provides controlled test data and a deletion mechanism. Using toRun: false avoids unnecessary execution during setup.


58-83: Good coverage of the deletion edge case.

This test verifies that per-item state maps correctly after item removal—a critical scenario for the bug fix.

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

🧹 Nitpick comments (1)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (1)

779-779: Consider cleanup logic for removed list items.

selectedValuesByItem accumulates entries for every item visited, but no cleanup occurs when list items are deleted or the list shrinks. For dynamic lists with frequent changes, this map grows unbounded.

Consider adding cleanup logic to prune stale entries, either:

  • When list size decreases (compare previous/current list length in componentDidUpdate)
  • Periodically cap the map size by removing oldest entries
  • Expose a method to reset per-item state

Not a blocker for this PR given the Chill review mode, but worth tracking for future optimization.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21fcf6d and fced85b.

📒 Files selected for processing (1)
  • app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (5 hunks)
🔇 Additional comments (3)
app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx (3)

783-791: LGTM - Clean stable ID fallback.

The helper correctly prioritizes stable listItemId when available and falls back to index-based keys, ensuring consistent string keys for the selection map.


843-871: LGTM - Clean on-demand initialization.

syncSelectionMapOnIndexChange correctly initializes missing per-item entries without attempting to reorganize or shift existing entries. The stable key approach via getListItemId prevents the index-mapping issues flagged in prior reviews.

Minor note: previousRowIndex parameter is unused but doesn't hurt.


824-835: Type mismatch: defaultOptionValue assigned to LabelInValueType[] without conversion.

defaultOptionValue is typed as string[] | OptionValue[] (line 1040), but at lines 828 and 863 it's assigned/cast to LabelInValueType[] without conversion. When defaultOptionValue is a string array like ["GREEN", "RED"], it doesn't match the { label, value } shape expected by LabelInValueType[].

Verify that string arrays are properly transformed before storage, or update the type of selectedValuesByItem to accept both formats.

Comment on lines 820 to 822
if (hasChanges && this.props.isDirty) {
this.props.updateWidgetMetaProperty("isDirty", false);
}
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 | 🔴 Critical

Critical: isDirty reset exposes user selections to overwrite on subsequent default changes.

After the first defaultOptionValue change while the user has made selections, isDirty is reset to false (line 821). This causes the next defaultOptionValue change to overwrite the user's selection via lines 824-835, defeating per-item persistence for dynamic defaults.

Trace:

  1. User selects ["BLUE"]isDirty=true, selectedValuesByItem[itemId]=["BLUE"]
  2. Default changes to ["RED"] → isDirty reset to false, user selection preserved
  3. Default changes to ["YELLOW"] → lines 824-835 execute, user selection overwritten

Remove the isDirty reset to preserve selections across all default changes:

-    if (hasChanges && this.props.isDirty) {
-      this.props.updateWidgetMetaProperty("isDirty", false);
-    }
-
     if (hasChanges && !this.props.isDirty) {
🤖 Prompt for AI Agents
In app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx around lines
820-822, remove the unconditional reset of isDirty (the
this.props.updateWidgetMetaProperty("isDirty", false) call) so that per-item
user selections remain persistent across subsequent defaultOptionValue changes;
simply delete that line (or gate it behind a specific condition if there is a
legitimate one elsewhere), and run relevant unit/integration tests to ensure no
other logic relies on this reset.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: MultiSelect widget not working properly inside List Widget

4 participants