Skip to content

fix(actions): fix state mutation and retain newest actions when limit is reached#34107

Closed
sukets16 wants to merge 1 commit into
storybookjs:nextfrom
sukets16:fix/actions-addon-limit-bug
Closed

fix(actions): fix state mutation and retain newest actions when limit is reached#34107
sukets16 wants to merge 1 commit into
storybookjs:nextfrom
sukets16:fix/actions-addon-limit-bug

Conversation

@sukets16
Copy link
Copy Markdown

@sukets16 sukets16 commented Mar 11, 2026

Summary

Fixes #34052

The addAction callback in the Actions addon had two bugs:

1. State mutation

previous.count++ and action.count = 1 mutated objects directly inside a React state updater, violating immutability and potentially causing reconciliation issues.

2. Wrong slice direction

slice(0, limit) kept the oldest actions and discarded the newest when the limit was reached. Changed to slice(-limit) so the most recent actions are retained.

Changes

  • code/core/src/actions/containers/ActionLogger/addAction.ts -- Extracted the state update logic into a pure computeAddAction function that creates new objects instead of mutating, and uses slice(-limit) to keep newest entries.
  • code/core/src/actions/containers/ActionLogger/index.tsx -- Simplified the component to use the extracted function.
  • code/core/src/actions/containers/ActionLogger/addAction.test.ts -- 7 unit tests covering: adding actions, count incrementing, immutability of inputs, immutability of previous state, limit retaining newest, limit with count increment, and distinct action entries.
  • docs/essentials/actions.mdx -- Documented the limit parameter (type, default value, behavior when reached).

Checklist from #34052

  • Ensuring that we retain new messages, not old ones
  • Checking documentation to ensure the limit parameter is documented, and that what happens when the limit is reached is also documented
  • Adding stories that showcase the behaviour of addon panel when the limit is reached (the Actions addon has no existing stories; unit tests for the extracted logic cover limit behavior instead)

Summary by CodeRabbit

  • New Features

    • Added a limit parameter (default 50) to control the maximum number of displayed actions; oldest actions are discarded when the limit is reached.
    • Actions with identical data now group into a single entry with an incrementing count.
  • Tests

    • Added comprehensive tests covering add/group/limit behaviors and immutability.
  • Documentation

    • Updated docs describing the new limit parameter.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 11, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 59d9ed71-7c23-4b5d-95c2-525bce35e8ad

📥 Commits

Reviewing files that changed from the base of the PR and between 68194e8 and f3f46ad.

📒 Files selected for processing (4)
  • code/core/src/actions/containers/ActionLogger/addAction.test.ts
  • code/core/src/actions/containers/ActionLogger/addAction.ts
  • code/core/src/actions/containers/ActionLogger/index.tsx
  • docs/essentials/actions.mdx

📝 Walkthrough

Walkthrough

Extracts action-list management into a new computeAddAction utility that enforces deep-equality-based counting and a configurable limit. Replaces prior inline logic in the ActionLogger component, adds tests for computeAddAction, and documents a new limit parameter (default 50).

Changes

Cohort / File(s) Summary
New Action utility
code/core/src/actions/containers/ActionLogger/addAction.ts
Introduces computeAddAction(prevActions, action) with safeDeepEqual, DEFAULT_LIMIT=50, uses action.options.limit when present, increments last action count on deep-equal data, appends otherwise, and trims to the limit.
Component update
code/core/src/actions/containers/ActionLogger/index.tsx
Replaces inline deep-equality and add logic with a call to computeAddAction(prevActions, action), removes local safeDeepEqual and related branching.
Tests
code/core/src/actions/containers/ActionLogger/addAction.test.ts
Adds comprehensive tests validating empty-state adds, count incrementing for duplicate actions, immutability of inputs/previous state, limit trimming behavior, and handling of distinct actions.
Docs
docs/essentials/actions.mdx
Documents new limit parameter (Type: number, Default: 50) for Actions API, describing that oldest actions are removed when the limit is exceeded.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


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
Copy Markdown
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)
code/core/src/actions/containers/ActionLogger/addAction.test.ts (1)

62-86: Consider adding a test for undefined limit.

Given that ActionOptions is a Partial<Options> type and limit could be undefined at runtime, consider adding a test that verifies the behavior when options.limit is undefined to document the expected behavior.

📝 Example test case
it('handles undefined limit gracefully', () => {
  const action = createAction({
    id: '1',
    options: { clearOnStoryChange: true } as ActionDisplay['options'], // no limit
  });
  const result = computeAddAction([], action);
  
  expect(result).toHaveLength(1);
  // Document expected behavior - either uses default or allows unlimited
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/actions/containers/ActionLogger/addAction.test.ts` around lines
62 - 86, Add a test in addAction.test.ts that covers when an action's
options.limit is undefined: use createAction to make an action with options that
omit limit (e.g., { clearOnStoryChange: true } as ActionDisplay['options']),
call computeAddAction([], action), and assert the resulting state behavior
(e.g., result has length 1 or matches the code's documented default/unlimited
behavior); reference computeAddAction, createAction, and
ActionDisplay/ActionOptions in the test to clearly document expected handling of
undefined limit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/core/src/actions/containers/ActionLogger/addAction.ts`:
- Around line 22-26: The code uses action.options.limit directly in
slice(-action.options.limit) which fails when limit is undefined
(slice(-undefined) === slice(0)), so defensively resolve a numeric limit first
and use it in both return paths; e.g., compute const limit = typeof
action.options?.limit === "number" ? action.options.limit :
<DEFAULT_LIMIT_FROM_ActionOptions_OR_FALLBACK> (or import the default from
ActionOptions), then replace slice(-action.options.limit) with slice(-limit) for
updated and [...prevActions, newAction].slice(-limit); reference
action.options.limit, prevActions, updated, and newAction when making the
change.

---

Nitpick comments:
In `@code/core/src/actions/containers/ActionLogger/addAction.test.ts`:
- Around line 62-86: Add a test in addAction.test.ts that covers when an
action's options.limit is undefined: use createAction to make an action with
options that omit limit (e.g., { clearOnStoryChange: true } as
ActionDisplay['options']), call computeAddAction([], action), and assert the
resulting state behavior (e.g., result has length 1 or matches the code's
documented default/unlimited behavior); reference computeAddAction,
createAction, and ActionDisplay/ActionOptions in the test to clearly document
expected handling of undefined limit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4cad208-9e27-486d-ba97-8a1a8821db67

📥 Commits

Reviewing files that changed from the base of the PR and between 1ba2d07 and 68194e8.

📒 Files selected for processing (4)
  • code/core/src/actions/containers/ActionLogger/addAction.test.ts
  • code/core/src/actions/containers/ActionLogger/addAction.ts
  • code/core/src/actions/containers/ActionLogger/index.tsx
  • docs/essentials/actions.mdx

Comment thread code/core/src/actions/containers/ActionLogger/addAction.ts Outdated
… is reached

The addAction callback in the Actions addon had two bugs:

1. State mutation: previous.count++ and action.count = 1 mutated objects
   directly, violating React's immutability principle.
2. Wrong slice direction: slice(0, limit) kept the oldest actions and
   discarded the newest. Changed to slice(-limit) to retain recent entries.

Extracted the state update logic into a pure computeAddAction function
for testability, and added unit tests covering immutability, limit
behavior, and count incrementing.

Also documented the limit parameter in the actions addon docs.

Closes storybookjs#34052
@sukets16 sukets16 force-pushed the fix/actions-addon-limit-bug branch from 68194e8 to f3f46ad Compare March 11, 2026 20:13
@valentinpalkovic
Copy link
Copy Markdown
Contributor

Closing in favour of #34053

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Potential logic bug with options.limit in Actions addon

2 participants