Skip to content

Actions: Add expandLevel parameter to configure tree depth#33977

Merged
valentinpalkovic merged 3 commits intostorybookjs:nextfrom
mixelburg:fix/addon-actions-expand-level
Mar 6, 2026
Merged

Actions: Add expandLevel parameter to configure tree depth#33977
valentinpalkovic merged 3 commits intostorybookjs:nextfrom
mixelburg:fix/addon-actions-expand-level

Conversation

@mixelburg
Copy link
Copy Markdown

@mixelburg mixelburg commented Mar 2, 2026

What this PR does

Adds an expandLevel parameter to the actions addon configuration, allowing users to control how deep the action object tree is initially expanded in the panel.

The addon uses react-inspector's Inspector component which already supports an expandLevel prop — this PR exposes it as a configurable story parameter.

How to use

// .storybook/preview.ts  (global)
const preview = {
  parameters: {
    actions: { expandLevel: 2 },
  },
};
// Individual story
const meta = {
  parameters: {
    actions: { expandLevel: 3 },
  },
};

The default value is 1 (same as before — no visible change for existing users).

Closes

Closes #22390

Summary by CodeRabbit

  • New Features

    • Configurable initial expansion level for the action inspector (controls how many tree levels are expanded on load; default: 1).
  • Refactor

    • Action logger rewritten to a modern implementation for more reliable, responsive action capture and display.
  • Documentation

    • Updated docs describing the new expansion-level parameter and usage.

Fixes storybookjs#22390

The react-inspector's `Inspector` component supports an `expandLevel` prop
that controls how deep the action tree is initially expanded. This makes
it configurable via story parameters.

Example usage:
```ts
const meta = {
  parameters: {
    actions: { expandLevel: 2 },
  },
};
```
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b29cd2d6-4c27-4104-b875-020e6def5c9d

📥 Commits

Reviewing files that changed from the base of the PR and between 7e5ffd5 and 179914e.

📒 Files selected for processing (1)
  • docs/essentials/actions.mdx

📝 Walkthrough

Walkthrough

Adds an optional expandLevel parameter and threads it from parameters → container → presentational ActionLogger → ThemedInspector; refactors the container to a functional component using hooks, parameter-driven expandLevel, and hook-based event subscription and action management.

Changes

Cohort / File(s) Summary
Types
code/core/src/actions/types.ts
Added expandLevel?: number to ActionsParameters.actions with JSDoc default 1.
Presentational component
code/core/src/actions/components/ActionLogger/index.tsx
Added expandLevel?: number to InspectorProps and ActionLoggerProps; updated component signature to accept expandLevel and pass expandLevel={expandLevel} to ThemedInspector.
Container / behavior
code/core/src/actions/containers/ActionLogger/index.tsx
Refactored class → functional component using hooks; reads expandLevel from parameters via useParameter(PARAM_KEY) (default 1); replaced lifecycle-based listeners with useEffect subscriptions for events and STORY_CHANGED; reimplemented actions state as immutable useState with addAction, clearActions, dedupe/counting and limit logic; passes expandLevel to presentational component via memoized props.

Sequence Diagram(s)

sequenceDiagram
  participant API as Storybook API
  participant Container as ActionLogger Container
  participant Component as ActionLogger Component
  participant Inspector as ThemedInspector

  API->>Container: mount / provide params
  Container->>API: useParameter(PARAM_KEY) => expandLevel
  Container->>API: register EVENT_ID listener
  Container->>API: register STORY_CHANGED listener

  API->>Container: EVENT_ID (new action)
  Container->>Container: addAction (dedupe/count/limit)
  Container->>Component: props{ actions, expandLevel, onClear }

  Component->>Inspector: render with expandLevel
  Component->>Container: onClear()
  Container->>API: emit CLEAR_ID
  Container->>Container: reset actions
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 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

🤖 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/index.tsx`:
- Around line 49-51: Create a single normalized resolver for the expandLevel
parameter so invalid values can't reach state: add a helper function (e.g.,
normalizeExpandLevel) that reads the raw value via
api.getCurrentParameter<ActionsParameters['actions']>(PARAM_KEY), coerces it to
a safe integer >= 1 (handle NaN, floats, negatives by using Number conversion
and Math.floor or default to 1), and then use that helper wherever expandLevel
is set (replace the inline reads before this.setState and at the other
occurrence around the lines using expandLevel); ensure calls reference the
PARAM_KEY and update setState({ expandLevel }) with the sanitized value.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4d647b and 9b5d17e.

📒 Files selected for processing (3)
  • code/core/src/actions/components/ActionLogger/index.tsx
  • code/core/src/actions/containers/ActionLogger/index.tsx
  • code/core/src/actions/types.ts

Comment thread code/core/src/actions/containers/ActionLogger/index.tsx Outdated
@valentinpalkovic valentinpalkovic self-assigned this Mar 5, 2026
@valentinpalkovic valentinpalkovic moved this to Empathy Queue (prioritized) in Core Team Projects Mar 5, 2026
@valentinpalkovic valentinpalkovic moved this from Empathy Queue (prioritized) to In Progress in Core Team Projects Mar 5, 2026
Copy link
Copy Markdown
Contributor

@valentinpalkovic valentinpalkovic left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for your contribution :)

@valentinpalkovic valentinpalkovic changed the title Actions: add expandLevel parameter to configure tree depth Actions: Add expandLevel parameter to configure tree depth Mar 5, 2026
@valentinpalkovic
Copy link
Copy Markdown
Contributor

valentinpalkovic commented Mar 6, 2026

Hi @mixelburg

Thank you for your contribution! When trying it out, the solution unfortunately didn't work. I think it had something to do with api.getCurrentParameter not being reactive. I've changed the ActionLogger component from a class to a function and things started to work!

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/index.tsx (1)

51-65: Frequent re-subscription due to handleStoryChange depending on actions.

Since handleStoryChange includes actions in its dependency array, it recreates on every action addition. This triggers the useEffect to unsubscribe and resubscribe to STORY_CHANGED, which is inefficient and could miss events during the transition window.

Use a ref to access the latest actions without triggering callback recreation:

Proposed fix using ref pattern
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
 export default function ActionLogger({ active, api }: ActionLoggerProps) {
   const [actions, setActions] = useState<ActionDisplay[]>([]);
+  const actionsRef = useRef<ActionDisplay[]>(actions);
   const parameter = useParameter<ActionsParameters['actions']>(PARAM_KEY);
   const expandLevel = parameter?.expandLevel ?? 1;

+  useEffect(() => {
+    actionsRef.current = actions;
+  }, [actions]);
+
   // ... clearActions and addAction unchanged ...

   const handleStoryChange = useCallback(() => {
-    if (actions.length > 0 && actions[0].options.clearOnStoryChange) {
+    if (actionsRef.current.length > 0 && actionsRef.current[0].options.clearOnStoryChange) {
       clearActions();
     }
-  }, [actions, clearActions]);
+  }, [clearActions]);

   useEffect(() => {
     api.on(EVENT_ID, addAction);
     api.on(STORY_CHANGED, handleStoryChange);

     return () => {
       api.off(EVENT_ID, addAction);
       api.off(STORY_CHANGED, handleStoryChange);
     };
   }, [api, addAction, handleStoryChange]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/actions/containers/ActionLogger/index.tsx` around lines 51 -
65, handleStoryChange currently depends on actions so it is recreated on every
action add causing frequent api (STORY_CHANGED) unsubscribe/resubscribe; fix by
storing the latest actions in a ref (e.g., actionsRef) and update that ref
whenever actions change, then rewrite handleStoryChange to read
actionsRef.current and call clearActions if needed (remove actions from
handleStoryChange deps), keep clearActions, addAction and api in the outer
useEffect deps so the effect no longer resubscribes on every action addition.
🤖 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/index.tsx`:
- Around line 37-49: The updater in addAction mutates objects: newActions uses a
shallow copy so modifying previous.count and action.count mutates prior state
and the incoming object; fix by creating new objects instead of mutating—when
merging with the previous entry construct a new object (e.g., copy previous and
increment its count) and when pushing the incoming action create a newAction
copy with count = 1 rather than assigning to action.count; also change the final
slice to slice(-action.options.limit) (or handle undefined safely) so the most
recent actions are retained; reference addAction, setActions, previous,
safeDeepEqual, and action.options.limit when applying these changes.

---

Nitpick comments:
In `@code/core/src/actions/containers/ActionLogger/index.tsx`:
- Around line 51-65: handleStoryChange currently depends on actions so it is
recreated on every action add causing frequent api (STORY_CHANGED)
unsubscribe/resubscribe; fix by storing the latest actions in a ref (e.g.,
actionsRef) and update that ref whenever actions change, then rewrite
handleStoryChange to read actionsRef.current and call clearActions if needed
(remove actions from handleStoryChange deps), keep clearActions, addAction and
api in the outer useEffect deps so the effect no longer resubscribes on every
action addition.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e446d712-c23d-46a5-9eee-e7cdb2c63acf

📥 Commits

Reviewing files that changed from the base of the PR and between 9b5d17e and 7e5ffd5.

📒 Files selected for processing (1)
  • code/core/src/actions/containers/ActionLogger/index.tsx

Comment thread code/core/src/actions/containers/ActionLogger/index.tsx
@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot bot commented Mar 6, 2026

Package Benchmarks

Commit: 179914e, ran on 6 March 2026 at 11:08:59 UTC

No significant changes detected, all good. 👏

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

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Feature Request]: addon-actions allow inspector items to be expanded by default

3 participants