Skip to content

feat: integrate Storybook into the project#7204

Open
fairlighteth wants to merge 4 commits intodevelopfrom
feat/storybook
Open

feat: integrate Storybook into the project#7204
fairlighteth wants to merge 4 commits intodevelopfrom
feat/storybook

Conversation

@fairlighteth
Copy link
Copy Markdown
Contributor

@fairlighteth fairlighteth commented Mar 20, 2026

Summary

Adds a monorepo-root Storybook pilot for libs/ui, documents the shared Button surface, and removes dead/duplicate button variants as part of the initial component audit workflow.

Screenshot 2026-03-20 at 18 13 03

This PR:

  • adds root Storybook config, scripts, and CI build coverage
  • documents UI/Button with focused docs, state stories, and one real usage example
  • removes ButtonLight, which had 0 usage in the repo
  • replaces the only ButtonSecondaryAlt usage with compact ButtonSecondary props and deletes ButtonSecondaryAlt

To Test

  1. Run Storybook locally
  • Run pnpm storybook
  • Open http://localhost:6006
  • Verify the Storybook app loads successfully from the monorepo root
  1. Review Button docs and stories
  • Open UI / Button / Docs
  • Verify the docs page shows the main Button example, core states, and the Usage in Context banner example
  • Verify the usage snippet shows the compact ButtonSecondary props used for the banner case
  1. Review Button usage example
  • Open UI / Button / Usage / Inline Banner Secondary Action
  • Verify the compact dismiss button renders correctly inside the banner example
  • Open the Code panel and verify the example shows ButtonSecondary with compact props instead of ButtonSecondaryAlt
  1. Verify cleanup/consolidation behavior
  • Confirm ButtonLight is no longer available in stories
  • Confirm ButtonSecondaryAlt is no longer exported/used
  • Confirm the custom recipient warning banner still looks correct with the new compact ButtonSecondary
  1. Verify CI/build behavior
  • Run pnpm storybook:build
  • Verify the Storybook build completes successfully

Background

This is the first small pilot for using Storybook as the component audit/documentation surface.

Notes:

  • ButtonLight was deleted because it had 0 real usages in the repo
  • ButtonSecondaryAlt was deleted after confirming it had a single real consumer that could be replaced with ButtonSecondary plus compact styling props
  • the current scope is intentionally narrow to validate authoring, discoverability, and review workflow before expanding further

Follow-up PRs are expected to:

  • add more pilot components such as LinkText and Table
  • evaluate Storybook Vitest addon coverage and a11y testing in CI
  • continue consolidating shared UI surfaces where the audit shows duplication

Summary by CodeRabbit

  • New Features

    • Added Storybook with interactive component docs, global theming, preview layouts, and multiple new component stories
  • Refactor

    • Removed two legacy button variants and simplified button library
    • Made secondary button styling customizable (font-size, min-height)
    • Updated dismiss button to use the standardized secondary style
  • Chores

    • CI now builds Storybook and reports failures
    • Added Storybook scripts, ignored cache dir, and adjusted TypeScript/workspace configs

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cowfi Error Error Apr 8, 2026 8:46am
explorer-dev Error Error Apr 8, 2026 8:46am
swap-dev Error Error Apr 8, 2026 8:46am
widget-configurator Error Error Apr 8, 2026 8:46am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
cosmos Ignored Ignored Apr 8, 2026 8:46am
sdk-tools Ignored Ignored Preview Apr 8, 2026 8:46am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 20, 2026

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c884db36-706e-49e0-88ec-d0d5794dc147

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds Storybook (config, stories, scripts, deps), integrates Storybook build into CI with notifications, removes two button variants (ButtonLight, ButtonSecondaryAlt), updates ButtonSecondary and related fixtures/usages, and ignores /.cache in git.

Changes

Cohort / File(s) Summary
CI Workflow
.github/workflows/ci.yml
Add storybook job that installs deps and runs pnpm run storybook:build; update notify-failure to depend on storybook and include STORYBOOK_RESULT in notification env and failure aggregation.
Storybook Config
.storybook/main.ts, .storybook/preview.tsx, .storybook/tsconfig.json
New Storybook configuration: story globs, React+Vite framework, a11y/docs addons, Vite resolve/define logic, global theme/decorator, and Storybook-specific tsconfig.
Package + Workspace
package.json, pnpm-workspace.yaml, .gitignore
Add Storybook scripts and deps, pin React versions/types, exempt Storybook packages from release-age delay, and ignore /.cache.
UI Library Exports / TS Config
libs/ui/src/index.ts, libs/ui/tsconfig.lib.json
Remove re-export of ButtonSecondaryAlt; set moduleResolution: "bundler" for the UI lib tsconfig.
Button Component Changes
libs/ui/src/pure/Button/index.tsx, libs/ui/src/pure/Button/ButtonMod.tsx, libs/ui/src/pure/ButtonSecondaryAlt/index.tsx, libs/ui/src/pure/Button/__fixtures__/Button.tsx
Remove ButtonLight and delete ButtonSecondaryAlt file; update ButtonSecondary to accept optional $fontSize and $minHeight props and derive CSS from them; update fixtures to remove ButtonLight.
Button Stories & Usage
libs/ui/src/pure/Button/Button.stories.tsx, libs/ui/src/pure/Button/ButtonUsage.stories.tsx
Add Storybook stories and docs for buttons: interactive playground, variants, disabled states, size scale, and an inline usage story for secondary action.
App Usage Update
apps/cowswap-frontend/src/common/pure/CustomRecipientWarningBanner/index.tsx
Replace ButtonSecondaryAlt usage with ButtonSecondary, passing explicit styling props ($borderRadius, $fontSize, $minHeight, padding, width).

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Runner as CI Runner
    participant PNPM as pnpm / Storybook build
    participant Notify as notify-failure job
    participant Slack as Slack webhook

    GH->>Runner: start workflow (setup -> needs)
    Runner->>PNPM: run storybook job (install, pnpm run storybook:build)
    PNPM-->>Runner: storybook result (success/failure)
    Runner->>Notify: job results including needs.storybook.result
    Notify->>Slack: send aggregated failure message (includes STORYBOOK_RESULT)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰
I hopped into stories, bright and new,
Buttons pranced in a tidy view,
CI hums, builds, and sends a ping,
Docs bloom where the knobs now sing—
A carrot-toast to components true. 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: integrate Storybook into the project' clearly and concisely describes the main change—adding Storybook integration to the monorepo.
Description check ✅ Passed The PR description is comprehensive, covering summary, testing steps with checkboxes, background context, and includes a screenshot. However, it does not explicitly reference a linked issue number using 'Fixes #issueNumber' format as shown in the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/storybook

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 (4)
.storybook/main.ts (2)

92-94: Consider relocating getAbsolutePath before its usage.

The function is defined after it's used on lines 73-75. While JavaScript hoisting makes this work, placing helper functions before their call sites improves readability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.storybook/main.ts around lines 92 - 94, Move the helper function
getAbsolutePath so it is declared before its first use to improve readability;
locate the getAbsolutePath function and the code that calls it (the
import.meta.resolve + dirname usage) and cut the existing function definition
and paste it above the code block that invokes getAbsolutePath, keeping the same
signature function getAbsolutePath(value: string): string { return
dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`))) } and
preserving imports (dirname, fileURLToPath, import.meta.resolve) so behavior
remains unchanged.

30-30: Consider defensive parsing for package.json files.

JSON.parse will throw on malformed JSON. While unlikely in a controlled monorepo, adding a try-catch would make the build more resilient to corrupted or WIP package files.

🛡️ Proposed defensive parsing
 function getWorkspaceAlias(packageJsonPath: string): [string, string] | null {
   if (!existsSync(packageJsonPath)) {
     return null
   }

-  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as WorkspacePackageJson
+  let packageJson: WorkspacePackageJson
+  try {
+    packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as WorkspacePackageJson
+  } catch {
+    return null
+  }
   const entryPoint = getWorkspaceEntryPoint(packageJson)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.storybook/main.ts at line 30, Wrap the JSON.parse call that produces
packageJson from packageJsonPath in a try-catch to defensively handle malformed
package.json; inside the catch, log or surface the parse error (include
packageJsonPath and error) and set packageJson to a safe fallback typed as
WorkspacePackageJson (e.g., an empty object cast) or rethrow a clearer
error—update the code around the packageJson = JSON.parse(...) expression so
packageJson and its use-sites (symbol: packageJson) remain typed while avoiding
an uncaught exception from JSON.parse.
libs/ui/src/pure/Button/Button.stories.tsx (2)

79-90: Minor duplication with ButtonUsage.stories.tsx.

InlineBannerUsagePreview replicates the banner pattern from ButtonUsage.stories.tsx. Consider importing InlineBannerSecondaryAction story or extracting a shared component if maintaining sync becomes a burden.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@libs/ui/src/pure/Button/Button.stories.tsx` around lines 79 - 90,
InlineBannerUsagePreview duplicates the banner pattern found in
ButtonUsage.stories.tsx; replace the duplication by reusing the existing story
or shared component: import the InlineBannerSecondaryAction story/component from
ButtonUsage.stories (or extract a new shared InlineBanner component) and use
that inside Button.stories.tsx instead of recreating the JSX, ensuring you
reference InlineBannerUsagePreview (to remove) and InlineBannerSecondaryAction
or the new InlineBanner component (to import/use) so both stories stay in sync.

1-246: File is at 246 LOC — close to the 250-line limit.

This comprehensive story file with a custom docs page justifies the length, but consider splitting if more stories are added. The custom ButtonDocsPage (lines 92-112) could move to a separate Button.docs.tsx file if the story count grows.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@libs/ui/src/pure/Button/Button.stories.tsx` around lines 1 - 246, The file is
nearing the 250-line limit; extract the custom docs page into its own module to
keep the story file smaller: create a new file that exports the existing
ButtonDocsPage function (keep the JSX and any helper components it uses like
InlineBannerUsagePreview and the docs strings), update the story meta to import
and reference the exported ButtonDocsPage in parameters.docs.page, and remove
the ButtonDocsPage implementation from Button.stories.tsx (leaving any small
helpers used only by docs either moved with it or replaced by imports). Ensure
symbols referenced are ButtonDocsPage, InlineBannerUsagePreview (if moved), and
the meta object’s parameters.docs.page so the story continues to use the
external docs component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Around line 20-21: The Storybook npm scripts "storybook" and "storybook:build"
currently set env vars using POSIX syntax which fails on Windows; update both
scripts to prefix their environment assignments with cross-env (e.g., use
cross-env STORYBOOK_DISABLE_TELEMETRY=1 HOME=.cache/storybook-home ...) so that
the variables are applied cross-platform when running the "storybook" and
"storybook:build" scripts.

---

Nitpick comments:
In @.storybook/main.ts:
- Around line 92-94: Move the helper function getAbsolutePath so it is declared
before its first use to improve readability; locate the getAbsolutePath function
and the code that calls it (the import.meta.resolve + dirname usage) and cut the
existing function definition and paste it above the code block that invokes
getAbsolutePath, keeping the same signature function getAbsolutePath(value:
string): string { return
dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`))) } and
preserving imports (dirname, fileURLToPath, import.meta.resolve) so behavior
remains unchanged.
- Line 30: Wrap the JSON.parse call that produces packageJson from
packageJsonPath in a try-catch to defensively handle malformed package.json;
inside the catch, log or surface the parse error (include packageJsonPath and
error) and set packageJson to a safe fallback typed as WorkspacePackageJson
(e.g., an empty object cast) or rethrow a clearer error—update the code around
the packageJson = JSON.parse(...) expression so packageJson and its use-sites
(symbol: packageJson) remain typed while avoiding an uncaught exception from
JSON.parse.

In `@libs/ui/src/pure/Button/Button.stories.tsx`:
- Around line 79-90: InlineBannerUsagePreview duplicates the banner pattern
found in ButtonUsage.stories.tsx; replace the duplication by reusing the
existing story or shared component: import the InlineBannerSecondaryAction
story/component from ButtonUsage.stories (or extract a new shared InlineBanner
component) and use that inside Button.stories.tsx instead of recreating the JSX,
ensuring you reference InlineBannerUsagePreview (to remove) and
InlineBannerSecondaryAction or the new InlineBanner component (to import/use) so
both stories stay in sync.
- Around line 1-246: The file is nearing the 250-line limit; extract the custom
docs page into its own module to keep the story file smaller: create a new file
that exports the existing ButtonDocsPage function (keep the JSX and any helper
components it uses like InlineBannerUsagePreview and the docs strings), update
the story meta to import and reference the exported ButtonDocsPage in
parameters.docs.page, and remove the ButtonDocsPage implementation from
Button.stories.tsx (leaving any small helpers used only by docs either moved
with it or replaced by imports). Ensure symbols referenced are ButtonDocsPage,
InlineBannerUsagePreview (if moved), and the meta object’s parameters.docs.page
so the story continues to use the external docs component.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 25cc1acb-fe63-46a5-b294-51a488acb624

📥 Commits

Reviewing files that changed from the base of the PR and between b32f794 and 29b4786.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • .github/workflows/ci.yml
  • .gitignore
  • .storybook/main.ts
  • .storybook/preview.tsx
  • .storybook/tsconfig.json
  • apps/cowswap-frontend/src/common/pure/CustomRecipientWarningBanner/index.tsx
  • libs/ui/src/index.ts
  • libs/ui/src/pure/Button/Button.stories.tsx
  • libs/ui/src/pure/Button/ButtonMod.tsx
  • libs/ui/src/pure/Button/ButtonUsage.stories.tsx
  • libs/ui/src/pure/Button/__fixtures__/Button.tsx
  • libs/ui/src/pure/Button/index.tsx
  • libs/ui/src/pure/ButtonSecondaryAlt/index.tsx
  • libs/ui/tsconfig.lib.json
  • package.json
  • pnpm-workspace.yaml
💤 Files with no reviewable changes (3)
  • libs/ui/src/pure/Button/ButtonMod.tsx
  • libs/ui/src/pure/ButtonSecondaryAlt/index.tsx
  • libs/ui/src/index.ts

Comment on lines +20 to +21
"storybook": "STORYBOOK_DISABLE_TELEMETRY=1 HOME=.cache/storybook-home storybook dev -p 6006",
"storybook:build": "STORYBOOK_DISABLE_TELEMETRY=1 HOME=.cache/storybook-home storybook build --output-dir build/storybook",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify scripts that use inline env assignment without cross-env
python - <<'PY'
import json, re
with open("package.json") as f:
    pkg = json.load(f)
for name, cmd in pkg.get("scripts", {}).items():
    if re.match(r'^[A-Z_]+=.*', cmd) and "cross-env" not in cmd:
        print(f"{name}: {cmd}")
PY

Repository: cowprotocol/cowswap

Length of output: 271


🏁 Script executed:

#!/bin/bash
# Check if cross-env is already a dependency in package.json
jq '.devDependencies, .dependencies' package.json | grep -i "cross-env"

Repository: cowprotocol/cowswap

Length of output: 87


🏁 Script executed:

#!/bin/bash
# Check for all scripts using POSIX-style env assignment without cross-env
python - <<'PY'
import json, re
with open("package.json") as f:
    pkg = json.load(f)
all_issues = []
for name, cmd in pkg.get("scripts", {}).items():
    if re.match(r'^[A-Z_]+=', cmd) and "cross-env" not in cmd:
        all_issues.append(f"{name}: {cmd}")

if all_issues:
    print("Scripts with POSIX env assignment (no cross-env):")
    for issue in all_issues:
        print(f"  {issue}")
else:
    print("No other issues found")
PY

Repository: cowprotocol/cowswap

Length of output: 325


Use cross-env for Storybook scripts to keep cross-platform execution reliable.

Lines 20–21 currently use POSIX-style env assignment; these commands fail in Windows shells. Since cross-env is already a dependency, wrap both scripts:

-    "storybook": "STORYBOOK_DISABLE_TELEMETRY=1 HOME=.cache/storybook-home storybook dev -p 6006",
-    "storybook:build": "STORYBOOK_DISABLE_TELEMETRY=1 HOME=.cache/storybook-home storybook build --output-dir build/storybook",
+    "storybook": "cross-env STORYBOOK_DISABLE_TELEMETRY=1 HOME=.cache/storybook-home storybook dev -p 6006",
+    "storybook:build": "cross-env STORYBOOK_DISABLE_TELEMETRY=1 HOME=.cache/storybook-home storybook build --output-dir build/storybook",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 20 - 21, The Storybook npm scripts "storybook" and
"storybook:build" currently set env vars using POSIX syntax which fails on
Windows; update both scripts to prefix their environment assignments with
cross-env (e.g., use cross-env STORYBOOK_DISABLE_TELEMETRY=1
HOME=.cache/storybook-home ...) so that the variables are applied cross-platform
when running the "storybook" and "storybook:build" scripts.

@fairlighteth fairlighteth self-assigned this Mar 20, 2026
@socket-security
Copy link
Copy Markdown

socket-security bot commented Apr 7, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​storybook/​react-vite@​10.3.19910073100100
Added@​storybook/​react@​10.3.110010077100100
Added@​storybook/​addon-a11y@​10.3.110010078100100
Added@​storybook/​addon-docs@​10.3.199100100100100

View full report

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.

1 participant