Skip to content

Conversation

@saddlepaddle
Copy link
Collaborator

@saddlepaddle saddlepaddle commented Nov 5, 2025

  • WIP - fresh storybook setup
  • Tailwind + fonts working
  • WIP - trying to figure out screenshotting
  • Test ci/cd as well

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes


Important

Set up Storybook and Chromatic for visual testing and component documentation with Next.js and Vite integration.

  • Setup:
    • Add Storybook configuration in .storybook/main.ts for Next.js and Vite.
    • Integrate Chromatic with GitHub Actions in chromatic.yml for visual regression testing.
  • Components:
    • Add mock components in mocks/trpc-react.tsx for Storybook testing.
    • Create presentational components like SelectProjectPresentation and TopBarPresentation.
  • Stories:
    • Add stories for components in stories/ directory, including Button.stories.ts and ProjectsPage.stories.tsx.
  • Scripts and Dependencies:
    • Add scripts for Storybook and Chromatic in package.json.
    • Update devDependencies with Storybook and Chromatic packages.

This description was created by Ellipsis for 01ce483. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Complete Storybook-driven component library with many UI pieces (project lists, project cards, top bar, template modal) and interactive stories/docs.
    • Chromatic publishing integrated for automatic visual snapshots.
    • Browser-based testing via Vitest + Playwright with Storybook test setup.
  • Chores

    • Added developer scripts, ESLint Storybook rules, testing/configuration, Next.js build lint skip, and .gitignore entries to support Storybook, CI, and local workflows.

@vercel
Copy link

vercel bot commented Nov 5, 2025

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

Project Deployment Preview Comments Updated (UTC)
web Ready Ready Preview Comment Nov 6, 2025 0:39am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
docs Skipped Skipped Nov 6, 2025 0:39am

@supabase
Copy link

supabase bot commented Nov 5, 2025

This pull request has been ignored for the connected project wowaemfasoptxrdjhilu because there are no changes detected in apps/backend/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai
Copy link

coderabbitai bot commented Nov 5, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds Storybook (config, preview, mocks, stories, styles), Vitest test setup, Chromatic CI (GitHub Actions + chromatic.config), Storybook-related package and ESLint updates, and several presentational project-selection React components and their stories for the web client.

Changes

Cohort / File(s) Summary
CI: Chromatic workflow
\.github/workflows/chromatic.yml
New GitHub Actions workflow to set up Bun, install deps, and run Chromatic for apps/web/client using build-storybook.
Storybook core & CI config
apps/web/client/.storybook/main.ts, apps/web/client/.storybook/preview.tsx, apps/web/client/chromatic.config.json, apps/web/client/vitest.config.ts, apps/web/client/vitest.shims.d.ts, apps/web/client/.storybook/vitest.setup.ts
Adds Storybook main config, preview decorators/providers, metadata endpoint, Chromatic config, Vitest project config and shims, and Vitest Storybook setup.
Storybook mocks & aliases
apps/web/client/.storybook/mocks/supabase-client.ts, apps/web/client/.storybook/mocks/trpc-react.tsx
Adds Supabase storage stubs and a tRPC React mock provider (QueryClient + mock client) and exposes mock types/providers for stories.
Presentational project components
apps/web/client/src/app/projects/_components/*
.../select-presentation.tsx, .../select/project-card-presentation.tsx, .../select/square-project-card-presentation.tsx, .../templates/template-modal-presentation.tsx, .../top-bar-presentation.tsx
New pure/presentational React components for project gallery, project cards (card & square), template modal, and top bar with full prop-driven behavior.
Stories & docs
apps/web/client/src/stories/* (many: *.stories.ts, *.stories.tsx, Configure.mdx)
Adds numerous Storybook stories (Button, Header, Page, ProjectCard, ProjectsPage, SelectProject, TopBar) plus an MDX guide and story variants/playgrounds.
Sample UI components & styles
apps/web/client/src/stories/Button.tsx, Header.tsx, Page.tsx, apps/web/client/src/stories/*.css
Adds simple example components used by stories and corresponding CSS (button/header/page).
Tooling, lint, package & ignore
apps/web/client/.gitignore, apps/web/client/eslint.config.js, apps/web/client/package.json, apps/web/client/next.config.ts
Adds Storybook ignore patterns; integrates eslint-plugin-storybook into ESLint config; adds Storybook/Chromatic/Vitest scripts & devDependencies; sets eslint.ignoreDuringBuilds: true in Next.js config.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Developer (local)
  participant SB as Storybook (local/CI)
  participant Main as .storybook/main.ts
  participant Preview as .storybook/preview.tsx
  participant Mocks as .storybook/mocks
  participant Chromatic as Chromatic (CI)

  Dev->>SB: npm run storybook / build-storybook
  SB->>Main: load stories, addons, framework
  Main->>Mocks: resolve aliases -> substitute mocks
  SB->>Preview: apply decorators/providers
  Preview->>Mocks: initialize TRPC provider & Supabase stubs
  SB-->>Dev: rendered stories / built static site

  Note right of Chromatic: CI flow on push
  Chromatic->>Chromatic: checkout repo, setup Bun
  Chromatic->>SB: bun install --frozen-lockfile
  Chromatic->>SB: run build-storybook (apps/web/client)
  Chromatic->>Chromatic: upload snapshots (project token from secrets)
  Chromatic-->>Dev: CI result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Extra attention:
    • apps/web/client/.storybook/main.ts — path resolution, Git-root detection, Vite mergeConfig and dev/preview middleware serving /onbook-metadata.json.
    • apps/web/client/.storybook/mocks/trpc-react.tsx — QueryClient singleton, provider wiring, and types to ensure no runtime API calls.
    • Presentational components under apps/web/client/src/app/projects/_components/* — prop typings, search/sort logic, accessibility and event handling.
    • CI workflow and Chromatic config — workingDir, build script names, and secret usage.
    • apps/web/client/package.json & eslint.config.js — new dependencies and ESLint plugin integration.

Possibly related PRs

Suggested reviewers

  • Kitenite

Poem

🐇
I hopped through stories, tidy and bright,
Mocked the calls so components take flight,
Cards and templates in a neat row,
Chromatic blinked — the snapshots go,
A little rabbit cheers: hip-hop-hooray! 🎨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR description is largely incomplete and off-topic. Only bullet points and template remain unfilled; no substantive description of changes provided. Complete the Description section with a clear overview of changes. Check 'New feature', provide testing details, and remove placeholder comments or populate all sections per template.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main objective: setting up Storybook and Chromatic for testing, which aligns with the core changes in the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch storybook-setup

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.

{label}
<style jsx>{`
button {
background-color: ${backgroundColor};
Copy link
Contributor

Choose a reason for hiding this comment

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

The inline CSS uses background-color: ${backgroundColor} which might render as 'undefined' if backgroundColor isn't provided. Consider adding a default value.

Suggested change
background-color: ${backgroundColor};
background-color: ${backgroundColor || 'transparent'};

className="gap-2 border border-gray-300 w-auto cursor-pointer bg-white text-black hover:bg-gray-100"
>
<Icons.PencilPaper />
<p>Edit App</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo suggestion: The button label says 'Edit App' while this component represents a project card. Consider changing it to 'Edit Project' for consistency.

Suggested change
<p>Edit App</p>
<p>Edit Project</p>

alt="A book"
className="sb-explore-image"
/>
<p>Follow guided walkthroughs on for key workflows.</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: The sentence "Follow guided walkthroughs on for key workflows." contains an extra 'on'. Consider revising to "Follow guided walkthroughs for key workflows."

Suggested change
<p>Follow guided walkthroughs on for key workflows.</p>
<p>Follow guided walkthroughs for key workflows.</p>

Copy link

@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: 15

🧹 Nitpick comments (11)
apps/web/client/.gitignore (1)

51-52: Organize Storybook artifacts into a dedicated section.

The new Storybook patterns (*storybook.log and storybook-static) are appropriate ignores for build artifacts and logs, but they're placed under the # mastra section. Since these are Storybook-specific rather than mastra-specific, consider moving them to their own section (e.g., # storybook) or grouping them with other build outputs (like .next/, /out/, /build on lines 17–22) for better organization and clarity.

Apply this diff to organize the patterns more clearly:

- # mastra
- .mastra/
- 
- *storybook.log
- storybook-static
+ # mastra
+ .mastra/
+ 
+ # storybook
+ *storybook.log
+ storybook-static
apps/web/client/src/stories/Configure.mdx (1)

221-280: Update deprecated Next.js Image layout prop.

Lines 224, 240, 258, and 276 use the deprecated layout="fixed" prop. In Next.js 13+, this prop is deprecated in favor of explicit width and height without the layout prop.

Since you're already specifying width={32} and height={32}, simply remove the layout="fixed" prop:

 <Image 
   width={32}
   height={32}
-  layout="fixed"
   src={Github} 
   alt="Github logo" 
   className="sb-explore-image"
 />

Apply this change to all four instances (lines 224, 240, 258, 276).

apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx (1)

70-77: Consider adding aria-label to close button.

The close button at line 70 should have an aria-label for better accessibility, especially since it only contains an icon.

 <Button
     onClick={onClose}
     variant="ghost"
     size="sm"
     className="absolute top-4 right-4 z-10 p-2 rounded-full bg-background/20 hover:bg-secondary transition-colors"
+    aria-label="Close modal"
 >
     <Icons.CrossS className="w-4 h-4" />
 </Button>
apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx (1)

54-59: Consider making SHOW_DESCRIPTION a prop and simplifying handleEdit.

The hardcoded SHOW_DESCRIPTION constant at line 54 limits reusability. Consider making it a prop. Additionally, the handleEdit wrapper is redundant since you can use onClick={onEdit ? () => onEdit(project) : undefined} directly.

 interface ProjectCardPresentationProps {
     project: Project;
     imageUrl?: string | null;
     aspectRatio?: string;
     searchQuery?: string;
     HighlightText?: React.ComponentType<{ text: string; searchQuery: string }>;
     onEdit?: (project: Project) => void;
     onRename?: (project: Project) => void;
     onClone?: (project: Project) => void;
     onToggleTemplate?: (project: Project) => void;
     onDelete?: (project: Project) => void;
     isTemplate?: boolean;
+    showDescription?: boolean;
 }

 export function ProjectCardPresentation({
     project,
     imageUrl,
     aspectRatio = "aspect-[4/2.6]",
     searchQuery = "",
     HighlightText,
     onEdit,
     onRename,
     onClone,
     onToggleTemplate,
     onDelete,
     isTemplate = false,
+    showDescription = false,
 }: ProjectCardPresentationProps) {
-    const SHOW_DESCRIPTION = false;
     const lastUpdated = useMemo(() => timeAgo(project.metadata.updatedAt), [project.metadata.updatedAt]);

-    const handleEdit = () => {
-        onEdit?.(project);
-    };

Then use showDescription instead of SHOW_DESCRIPTION and onClick={() => onEdit?.(project)} instead of onClick={handleEdit}.

apps/web/client/src/stories/ProjectCard.stories.tsx (2)

1-41: Consider using ProjectCardPresentation for more isolated stories.

While using the stateful ProjectCard component works, you might get more predictable and faster-rendering stories by using ProjectCardPresentation (if available) since it removes the useEffect for image loading and all side effects. This would make stories more deterministic and easier to test.

If ProjectCardPresentation exists, you could import it instead:

import { ProjectCardPresentation } from '@/app/projects/_components/select/project-card-presentation';

Then pass pre-resolved image URLs as the imageUrl prop instead of relying on the storage resolution logic.


43-64: External image dependencies in stories.

The mock project generator uses Unsplash URLs for preview images. While this provides realistic visuals, it creates an external dependency. If Unsplash is unavailable or rate-limits requests, stories may not render properly.

For production Storybook deployments, consider:

  • Using local placeholder images in the public/ directory
  • Implementing image fallbacks
  • Documenting this dependency
.github/workflows/chromatic.yml (2)

3-3: Consider restricting the workflow trigger to specific branches.

The workflow currently triggers on all pushes, which may consume unnecessary CI resources and Chromatic snapshot quota on every branch and commit.

Consider limiting to main branch and PRs:

-on: push
+on:
+  push:
+    branches:
+      - main
+  pull_request:

24-24: Pin the Chromatic action version for stability.

Using @latest can introduce unexpected breaking changes in CI. Pin to a specific version for reproducible builds.

Apply this diff:

-      uses: chromaui/action@latest
+      uses: chromaui/action@v13
apps/web/client/.storybook/preview.tsx (1)

24-24: Consider making locale configurable.

The locale is hardcoded to "en", which means Storybook stories cannot demonstrate internationalized variants.

Consider using Storybook globals to allow switching locales:

// In preview.tsx parameters
parameters: {
  locale: 'en',
  locales: {
    en: 'English',
    // Add other locales as needed
  },
}

// In decorator
const locale = context.globals.locale || 'en';
<NextIntlClientProvider locale={locale} messages={messages[locale]}>
apps/web/client/src/stories/SelectProject.stories.tsx (1)

40-195: Consider extracting shared mock data to reduce duplication.

The createMockProject helper and mock project arrays are duplicated between this file and ProjectsPage.stories.tsx. Consider extracting them to a shared module like apps/web/client/src/stories/mocks/projects.ts for better maintainability.

Create a new file apps/web/client/src/stories/mocks/projects.ts:

import type { Project, User } from '@onlook/models';

export const createMockProject = (overrides?: Partial<Project>): Project => ({
  id: crypto.randomUUID(),
  name: 'Project Name',
  metadata: {
    createdAt: new Date('2024-01-01'),
    updatedAt: new Date('2024-11-01'),
    previewImg: {
      type: 'url',
      url: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80',
      updatedAt: new Date(),
    },
    description: 'Project description',
    tags: [],
  },
  ...overrides,
});

export const mockProjects: Project[] = [
  // ... move array content here
];

export const templateProjects: Project[] = [
  // ... move array content here
];

export const mockUser: User = {
  // ... from ProjectsPage.stories.tsx
};

Then import in both story files:

import { createMockProject, mockProjects, templateProjects } from '@/stories/mocks/projects';
apps/web/client/src/stories/ProjectsPage.stories.tsx (1)

82-251: Code duplication: extract shared mocks.

The createMockProject helper, mockProjects, and templateProjects arrays are duplicated from SelectProject.stories.tsx. The mockUser object should also be shared. See the refactoring suggestion in SelectProject.stories.tsx (lines 40-195) to extract all mock data to a shared module.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ccd2302 and b21b29e.

⛔ Files ignored due to path filters (16)
  • apps/web/client/src/stories/assets/accessibility.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/accessibility.svg is excluded by !**/*.svg
  • apps/web/client/src/stories/assets/addon-library.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/assets.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/context.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/discord.svg is excluded by !**/*.svg
  • apps/web/client/src/stories/assets/docs.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/figma-plugin.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/github.svg is excluded by !**/*.svg
  • apps/web/client/src/stories/assets/share.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/styling.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/testing.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/theming.png is excluded by !**/*.png
  • apps/web/client/src/stories/assets/tutorials.svg is excluded by !**/*.svg
  • apps/web/client/src/stories/assets/youtube.svg is excluded by !**/*.svg
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (32)
  • .github/workflows/chromatic.yml (1 hunks)
  • apps/web/client/.gitignore (1 hunks)
  • apps/web/client/.storybook/main.ts (1 hunks)
  • apps/web/client/.storybook/mocks/supabase-client.ts (1 hunks)
  • apps/web/client/.storybook/mocks/trpc-react.tsx (1 hunks)
  • apps/web/client/.storybook/preview.tsx (1 hunks)
  • apps/web/client/.storybook/vitest.setup.ts (1 hunks)
  • apps/web/client/chromatic.config.json (1 hunks)
  • apps/web/client/eslint.config.js (1 hunks)
  • apps/web/client/package.json (3 hunks)
  • apps/web/client/src/app/projects/_components/select-presentation.tsx (1 hunks)
  • apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx (1 hunks)
  • apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx (1 hunks)
  • apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx (1 hunks)
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx (1 hunks)
  • apps/web/client/src/stories/Button.stories.ts (1 hunks)
  • apps/web/client/src/stories/Button.stories.tsx (1 hunks)
  • apps/web/client/src/stories/Button.tsx (1 hunks)
  • apps/web/client/src/stories/Configure.mdx (1 hunks)
  • apps/web/client/src/stories/Header.stories.ts (1 hunks)
  • apps/web/client/src/stories/Header.tsx (1 hunks)
  • apps/web/client/src/stories/Page.stories.ts (1 hunks)
  • apps/web/client/src/stories/Page.tsx (1 hunks)
  • apps/web/client/src/stories/ProjectCard.stories.tsx (1 hunks)
  • apps/web/client/src/stories/ProjectsPage.stories.tsx (1 hunks)
  • apps/web/client/src/stories/SelectProject.stories.tsx (1 hunks)
  • apps/web/client/src/stories/TopBar.stories.tsx (1 hunks)
  • apps/web/client/src/stories/button.css (1 hunks)
  • apps/web/client/src/stories/header.css (1 hunks)
  • apps/web/client/src/stories/page.css (1 hunks)
  • apps/web/client/vitest.config.ts (1 hunks)
  • apps/web/client/vitest.shims.d.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/app/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env instead

Avoid hardcoded user-facing text; use next-intl messages/hooks

Files:

  • apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx
  • apps/web/client/src/app/projects/_components/select-presentation.tsx
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx
  • apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx
  • apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx
apps/web/client/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx
  • apps/web/client/src/app/projects/_components/select-presentation.tsx
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx
  • apps/web/client/src/stories/Page.tsx
  • apps/web/client/src/stories/Header.stories.ts
  • apps/web/client/src/stories/ProjectCard.stories.tsx
  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/Button.stories.tsx
  • apps/web/client/src/stories/Button.tsx
  • apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
  • apps/web/client/src/stories/Button.stories.ts
  • apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx
  • apps/web/client/src/stories/Header.tsx
  • apps/web/client/src/stories/Page.stories.ts
  • apps/web/client/src/stories/SelectProject.stories.tsx
apps/web/client/src/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain

apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'

Files:

  • apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx
  • apps/web/client/src/app/projects/_components/select-presentation.tsx
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx
  • apps/web/client/src/stories/Page.tsx
  • apps/web/client/src/stories/ProjectCard.stories.tsx
  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/Button.stories.tsx
  • apps/web/client/src/stories/Button.tsx
  • apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
  • apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx
  • apps/web/client/src/stories/Header.tsx
  • apps/web/client/src/stories/SelectProject.stories.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not use the any type unless necessary

Files:

  • apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx
  • apps/web/client/vitest.config.ts
  • apps/web/client/src/app/projects/_components/select-presentation.tsx
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx
  • apps/web/client/src/stories/Page.tsx
  • apps/web/client/src/stories/Header.stories.ts
  • apps/web/client/src/stories/ProjectCard.stories.tsx
  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/Button.stories.tsx
  • apps/web/client/src/stories/Button.tsx
  • apps/web/client/vitest.shims.d.ts
  • apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
  • apps/web/client/src/stories/Button.stories.ts
  • apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx
  • apps/web/client/src/stories/Header.tsx
  • apps/web/client/src/stories/Page.stories.ts
  • apps/web/client/src/stories/SelectProject.stories.tsx
apps/web/client/src/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs

Files:

  • apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx
  • apps/web/client/src/app/projects/_components/select-presentation.tsx
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx
  • apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx
  • apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx
{apps,packages}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Avoid using the any type unless absolutely necessary

Files:

  • apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx
  • apps/web/client/vitest.config.ts
  • apps/web/client/src/app/projects/_components/select-presentation.tsx
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx
  • apps/web/client/src/stories/Page.tsx
  • apps/web/client/src/stories/Header.stories.ts
  • apps/web/client/src/stories/ProjectCard.stories.tsx
  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/Button.stories.tsx
  • apps/web/client/src/stories/Button.tsx
  • apps/web/client/vitest.shims.d.ts
  • apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
  • apps/web/client/src/stories/Button.stories.ts
  • apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx
  • apps/web/client/src/stories/Header.tsx
  • apps/web/client/src/stories/Page.stories.ts
  • apps/web/client/src/stories/SelectProject.stories.tsx
🧠 Learnings (23)
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Use Bun for all installs and scripts; do not introduce npm, yarn, or pnpm

Applied to files:

  • apps/web/client/package.json
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Use Bun for all installs and scripts; do not use npm, yarn, or pnpm

Applied to files:

  • apps/web/client/package.json
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/next.config.ts : Import ./src/env in next.config.ts to enforce env validation at build time

Applied to files:

  • apps/web/client/vitest.config.ts
  • apps/web/client/.storybook/main.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries

Applied to files:

  • apps/web/client/src/app/projects/_components/select-presentation.tsx
  • apps/web/client/src/app/projects/_components/top-bar-presentation.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/{page,layout,route}.tsx : Follow App Router file conventions (page.tsx, layout.tsx, route.ts) within src/app

Applied to files:

  • apps/web/client/src/stories/Page.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable identities across renders

Applied to files:

  • apps/web/client/src/stories/Page.tsx
  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/layout.tsx : Preserve dark theme defaults via ThemeProvider usage in the root layout

Applied to files:

  • apps/web/client/.storybook/preview.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/layout.tsx : Preserve dark theme defaults via ThemeProvider in the root layout

Applied to files:

  • apps/web/client/.storybook/preview.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Avoid hardcoded user-facing text; use next-intl messages/hooks instead

Applied to files:

  • apps/web/client/.storybook/preview.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Avoid hardcoded user-facing text; use next-intl messages/hooks

Applied to files:

  • apps/web/client/.storybook/preview.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/next.config.ts : Import ./src/env in Next.js config to enforce env validation at build time

Applied to files:

  • apps/web/client/.storybook/preview.tsx
  • apps/web/client/.storybook/main.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*

Applied to files:

  • apps/web/client/.storybook/main.ts
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/trpc/react.tsx : Keep tRPC React client/provider behind a single client boundary in src/trpc/react.tsx

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/trpc/react.tsx : Keep tRPC React client provider(s) behind a client boundary (ensure this provider file is a client component)

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/server/api/root.ts : Export all tRPC routers from apps/web/client/src/server/api/root.ts

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/server/api/root.ts : Export all tRPC routers from src/server/api/root.ts

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/server/api/routers/**/*.ts : Place tRPC routers under apps/web/client/src/server/api/routers/**

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/server/api/routers/**/*.ts : Place tRPC routers under src/server/api/routers/**

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/server/api/routers/**/*.ts : Use publicProcedure/protectedProcedure from src/server/api/trpc.ts and validate inputs with Zod

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable references across renders

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/server/api/routers/**/*.ts : Use publicProcedure/protectedProcedure from apps/web/client/src/server/api/trpc.ts and validate inputs with Zod

Applied to files:

  • apps/web/client/.storybook/mocks/trpc-react.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/.next/** : Do not modify Next.js build outputs (.next)

Applied to files:

  • apps/web/client/.gitignore
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to **/.next/** : Do not modify Next.js build outputs (.next)

Applied to files:

  • apps/web/client/.gitignore
🧬 Code graph analysis (19)
apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx (4)
packages/ui/src/components/icons/index.tsx (1)
  • Icons (138-3667)
packages/ui/src/components/tooltip.tsx (3)
  • Tooltip (72-72)
  • TooltipTrigger (72-72)
  • TooltipContent (72-72)
packages/ui/src/components/dropdown-menu.tsx (4)
  • DropdownMenuTrigger (228-228)
  • DropdownMenuContent (216-216)
  • DropdownMenuItem (218-218)
  • DropdownMenuSeparator (223-223)
apps/web/client/src/app/projects/_components/templates/template-modal.tsx (1)
  • TemplateModal (39-252)
apps/web/client/vitest.config.ts (1)
.vscode/.debug.script.mjs (1)
  • __dirname (8-8)
apps/web/client/src/app/projects/_components/select-presentation.tsx (7)
packages/db/src/schema/project/project.ts (1)
  • projects (13-32)
apps/web/client/src/app/projects/_components/carousel/index.tsx (1)
  • Carousel (19-158)
apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx (1)
  • SquareProjectCardPresentation (21-92)
apps/web/client/src/app/projects/_components/select/highlight-text.tsx (1)
  • HighlightText (3-20)
apps/web/client/src/app/projects/_components/templates/index.tsx (1)
  • Templates (20-110)
apps/web/client/src/app/projects/_components/select/masonry-layout.tsx (1)
  • MasonryLayout (6-67)
apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx (1)
  • TemplateModalPresentation (37-193)
apps/web/client/src/app/projects/_components/top-bar-presentation.tsx (4)
packages/ui/src/components/icons/index.tsx (1)
  • Icons (138-3667)
packages/ui/src/components/dropdown-menu.tsx (3)
  • DropdownMenuTrigger (228-228)
  • DropdownMenuContent (216-216)
  • DropdownMenuItem (218-218)
apps/web/client/src/i18n/keys.ts (1)
  • transKeys (5-5)
packages/utility/src/initials.ts (1)
  • getInitials (1-7)
apps/web/client/src/stories/Page.tsx (1)
apps/web/client/src/stories/Header.tsx (1)
  • Header (15-54)
apps/web/client/src/stories/Header.stories.ts (1)
apps/web/client/src/stories/Header.tsx (1)
  • Header (15-54)
apps/web/client/src/stories/ProjectCard.stories.tsx (1)
apps/web/client/src/app/projects/_components/select/project-card.tsx (1)
  • ProjectCard (12-111)
apps/web/client/src/stories/TopBar.stories.tsx (1)
apps/web/client/src/app/projects/_components/top-bar-presentation.tsx (1)
  • TopBarPresentation (45-191)
apps/web/client/.storybook/preview.tsx (2)
apps/web/client/src/app/_components/theme.tsx (1)
  • ThemeProvider (6-11)
apps/web/client/.storybook/mocks/trpc-react.tsx (1)
  • TRPCReactProvider (42-63)
apps/web/client/src/stories/Button.stories.tsx (1)
apps/web/client/src/stories/Button.tsx (1)
  • Button (17-39)
apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx (4)
packages/utility/src/time.ts (1)
  • timeAgo (1-36)
packages/ui/src/components/dropdown-menu.tsx (3)
  • DropdownMenuTrigger (228-228)
  • DropdownMenuContent (216-216)
  • DropdownMenuItem (218-218)
packages/ui/src/components/icons/index.tsx (1)
  • Icons (138-3667)
apps/web/client/src/app/projects/_components/select/highlight-text.tsx (1)
  • HighlightText (3-20)
apps/web/client/src/stories/ProjectsPage.stories.tsx (2)
apps/web/client/src/app/projects/_components/top-bar-presentation.tsx (1)
  • TopBarPresentation (45-191)
apps/web/client/src/app/projects/_components/select-presentation.tsx (1)
  • SelectProjectPresentation (72-532)
apps/web/client/src/stories/Button.stories.ts (1)
apps/web/client/src/stories/Button.tsx (1)
  • Button (17-39)
apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx (3)
packages/utility/src/time.ts (1)
  • timeAgo (1-36)
apps/web/client/src/app/projects/_components/select/highlight-text.tsx (1)
  • HighlightText (3-20)
apps/web/client/src/app/projects/_components/select/square-project-card.tsx (1)
  • SquareProjectCard (11-107)
apps/web/client/src/stories/Header.tsx (1)
apps/web/client/src/stories/Button.tsx (1)
  • Button (17-39)
apps/web/client/eslint.config.js (1)
tooling/eslint/nextjs.js (2)
  • restrictEnvAccess (8-31)
  • restrictEnvAccess (8-31)
apps/web/client/.storybook/main.ts (1)
.vscode/.debug.script.mjs (1)
  • __dirname (8-8)
apps/web/client/src/stories/Page.stories.ts (2)
apps/web/client/src/stories/Page.tsx (1)
  • Page (10-73)
apps/web/client/src/stories/Header.stories.ts (2)
  • LoggedOut (34-34)
  • LoggedIn (26-32)
apps/web/client/src/stories/SelectProject.stories.tsx (1)
apps/web/client/src/app/projects/_components/select-presentation.tsx (1)
  • SelectProjectPresentation (72-532)
🪛 GitHub Actions: CI
apps/web/client/src/stories/TopBar.stories.tsx

[error] 4-4: Cannot find module '@storybook/addon-actions' or its corresponding type declarations.

apps/web/client/src/stories/ProjectsPage.stories.tsx

[error] 5-5: Cannot find module '@storybook/addon-actions' or its corresponding type declarations.

apps/web/client/src/stories/SelectProject.stories.tsx

[error] 4-4: Cannot find module '@storybook/addon-actions' or its corresponding type declarations.


[error] 221-221: Object is possibly 'undefined'.


[error] 407-407: Object is possibly 'undefined'.


[error] 407-407: Object is possibly 'undefined'.


[error] 432-432: Object is possibly 'undefined'.


[error] 488-488: Object is possibly 'undefined'.

🪛 Gitleaks (8.28.0)
apps/web/client/chromatic.config.json

[high] 2-2: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
apps/web/client/src/stories/Configure.mdx

[uncategorized] ~4-~4: The official name of this software platform is spelled with a capital “H”.
Context: ...import Image from "next/image"; import Github from "./assets/github.svg"; import Disc...

(GITHUB)


[uncategorized] ~4-~4: The official name of this software platform is spelled with a capital “H”.
Context: ...t/image"; import Github from "./assets/github.svg"; import Discord from "./assets/dis...

(GITHUB)


[uncategorized] ~6-~6: The official name of this popular video platform is spelled with a capital “T”.
Context: ...ord from "./assets/discord.svg"; import Youtube from "./assets/youtube.svg"; import Tut...

(YOUTUBE)


[uncategorized] ~6-~6: The official name of this popular video platform is spelled with a capital “T”.
Context: ...ord.svg"; import Youtube from "./assets/youtube.svg"; import Tutorials from "./assets/t...

(YOUTUBE)

🔇 Additional comments (33)
apps/web/client/src/stories/header.css (1)

1-32: Standard Storybook boilerplate styling.

This CSS file appears to be standard Storybook boilerplate for header styling. The structure and naming conventions are consistent with typical Storybook initialization.

apps/web/client/src/stories/Configure.mdx (1)

1-18: Standard Storybook configuration documentation.

This appears to be standard Storybook boilerplate documentation with customization for Next.js. The structure and content follow typical Storybook patterns for onboarding and configuration guides.

apps/web/client/src/stories/button.css (1)

1-30: Standard Storybook button styling.

This CSS file provides standard Storybook button variants and is consistent with typical Storybook initialization patterns.

apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsx (2)

1-31: Well-structured presentational component interface.

The component properly uses the 'use client' directive and defines a clear props interface. The separation between presentational and stateful components is a good architectural pattern.


106-186: Well-implemented action controls with proper conditional rendering.

The action buttons, tooltip, and dropdown menu are properly gated by the presence of their respective callback props. Loading states and accessibility labels are handled correctly.

apps/web/client/src/app/projects/_components/select/project-card-presentation.tsx (3)

1-35: Clean component interface with good prop documentation.

The props interface is well-structured with helpful JSDoc comments explaining the purpose of each callback and data prop.


84-162: Dropdown menu properly implemented with event handling.

The dropdown menu correctly prevents event propagation and implements conditional rendering based on available callbacks. The destructive styling for the delete action is appropriate.


164-206: Well-implemented card overlay and information display.

The hover overlay with the edit button and the bottom information section with conditional highlighting are well-executed. The use of HighlightText for search term highlighting improves UX.

apps/web/client/src/stories/ProjectCard.stories.tsx (1)

66-289: Comprehensive story coverage with good edge cases.

The story variants provide excellent coverage of different states and configurations: no images, varying ages, long names, search highlighting, and different aspect ratios. This will be valuable for visual regression testing with Chromatic.

apps/web/client/src/stories/page.css (1)

1-68: Standard Storybook page styling.

This CSS provides standard styling for Storybook documentation pages with appropriate typography, spacing, and callout elements. The structure is consistent with typical Storybook patterns.

apps/web/client/vitest.shims.d.ts (1)

1-1: LGTM! Type reference is correctly configured.

The triple-slash reference directive properly includes Playwright browser types for Vitest, aligning with the @vitest/browser-playwright dependency added in package.json.

apps/web/client/.storybook/vitest.setup.ts (1)

1-7: LGTM! Vitest setup correctly configures Storybook annotations.

The setup properly applies both accessibility addon annotations and project-specific annotations for portable stories testing, following the recommended pattern from Storybook documentation.

apps/web/client/vitest.config.ts (1)

1-37: LGTM! Vitest configuration properly integrates Storybook testing.

The configuration correctly:

  • Sets up Storybook test plugin with appropriate config directory
  • Configures Playwright browser provider for headless Chromium testing
  • References the Vitest setup file for portable stories annotations
  • Uses a dirname computation pattern consistent with the existing codebase
apps/web/client/.storybook/preview.tsx (2)

17-22: Clarify theme configuration: forcedTheme with enableSystem.

The ThemeProvider has both forcedTheme="dark" and enableSystem enabled. When forcedTheme is set, it overrides system preferences, making enableSystem ineffective.

If you want to respect system preferences in Storybook, remove forcedTheme:

 <ThemeProvider
   attribute="class"
-  forcedTheme="dark"
+  defaultTheme="dark"
   enableSystem
   disableTransitionOnChange
 >

Otherwise, if you want to force dark mode for consistent visual testing, remove enableSystem:

 <ThemeProvider
   attribute="class"
   forcedTheme="dark"
-  enableSystem
   disableTransitionOnChange
 >

41-46: LGTM! Accessibility testing appropriately configured for WIP.

Setting a11y.test to 'todo' is appropriate for this WIP PR, allowing you to see violations without blocking development. Remember to change this to 'error' before production to enforce accessibility standards in CI.

apps/web/client/package.json (2)

29-32: LGTM! Storybook scripts are properly configured.

The new scripts provide a complete Storybook workflow:

  • storybook: Development server on port 6006
  • build-storybook: Production build
  • preview-storybook: Preview built Storybook
  • chromatic: Chromatic integration with --exit-zero-on-changes flag

All scripts use Bun as per project guidelines.


119-145: I'll verify the dependency versions using an alternative approach since bun is unavailable in the sandbox.

Let me verify the actual package.json file to confirm the stated versions:Based on my verification, all dependency versions in the PR are stable and secure:

Storybook & Addons (10.0.4)
The latest version is 10.0.4, which is what the PR specifies. No direct vulnerabilities have been found for this package in Snyk's vulnerability database.

Playwright (1.56.1)
No direct vulnerabilities have been found for this package in Snyk's vulnerability database.

Vitest (4.0.7)
The PR pins vitest to ^4.0.7. Critical vulnerabilities affect versions starting from 1.0.0 before 1.6.1, all versions starting from 2.0.0 before 2.1.9, all versions starting from 3.0.0 before 3.0.5—none of which apply to version 4.0.7. The version specified is safe.

All packages are production-ready with no critical security concerns.

apps/web/client/src/stories/Page.tsx (1)

23-69: Replace hardcoded text with next-intl messages.

This component contains extensive hardcoded user-facing text that violates the coding guidelines for apps/web/client/src/**/*.tsx. Even for Storybook demo/documentation components, text should be internationalized.

Hardcoded text includes:

  • All headings, paragraphs, and links (lines 23-56)
  • The "Tip" callout text (lines 57-68)

As per coding guidelines.

Consider extracting all text to messages/en.json and using useTranslations('StorybookPage') to access them. This maintains consistency with the project's i18n approach and allows for future localization of Storybook documentation.

⛔ Skipped due to learnings
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Avoid hardcoded user-facing text; use next-intl messages/hooks
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Avoid hardcoded user-facing text; use next-intl messages/hooks instead
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/messages/** : Add or modify internationalized strings in apps/web/client/messages/* instead of hardcoding text
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/messages/**/*.{json,ts} : Add or modify translation keys in apps/web/client/messages/* and keep keys stable (prefer additions over breaking renames)
apps/web/client/eslint.config.js (1)

1-11: LGTM! Clean Storybook ESLint integration.

The Storybook ESLint plugin is properly integrated using the flat config format, and the configuration is correctly appended to the existing ESLint rules array.

apps/web/client/.storybook/mocks/supabase-client.ts (1)

1-33: LGTM! Well-designed Supabase mock for Storybook isolation.

The mock properly prevents the import chain that triggers process.cwd() and provides safe no-op implementations. The documentation clearly explains that stories should use type: 'url' for preview images.

apps/web/client/src/stories/Button.stories.ts (1)

1-54: LGTM! Well-structured Storybook stories.

The story configuration follows Storybook best practices with proper TypeScript typing, action spies, and comprehensive variant coverage.

apps/web/client/src/stories/Header.stories.ts (1)

1-34: LGTM! Clean Header story configuration.

The story properly demonstrates both logged-in and logged-out states with appropriate action handlers.

apps/web/client/src/stories/Button.stories.tsx (1)

1-88: LGTM! Comprehensive UI Button stories.

The stories provide excellent coverage of all button variants and sizes, including a helpful AllVariants overview. The use of icons demonstrates real-world usage patterns.

apps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsx (1)

21-92: Good presentational component design.

The component properly separates presentation from data fetching logic, making it ideal for Storybook stories and testing. Keyboard accessibility is well-implemented.

apps/web/client/.storybook/mocks/trpc-react.tsx (2)

17-24: Any types are acceptable for mock implementations.

While the coding guidelines discourage any types, using Record<string, any> for mock router types is appropriate here. This prevents importing the real AppRouter and its dependencies, which would trigger the dotenv.config() side effect.


42-63: LGTM! Well-designed tRPC mock provider.

The mock properly isolates Storybook from real API calls and follows best practices:

  • Singleton QueryClient pattern prevents duplicate instances
  • useState(() => api.createClient(...)) creates a stable client reference
  • Clear documentation explains the purpose

Based on learnings.

apps/web/client/src/stories/SelectProject.stories.tsx (3)

10-34: LGTM!

The Storybook meta configuration is well-structured with appropriate layout, background, and argTypes definitions.


198-209: LGTM!

Action callbacks are properly defined for tracking component interactions in Storybook.


214-505: Excellent story coverage!

The story variants comprehensively cover different UI states and data scenarios, providing valuable documentation and testing for the SelectProjectPresentation component.

apps/web/client/src/stories/ProjectsPage.stories.tsx (4)

12-61: LGTM!

The ProjectsPageComposed component properly combines the TopBar and SelectProject presentations with shared state management for search functionality. This is an effective pattern for full-page Storybook stories.


66-76: LGTM!

The Storybook meta configuration is properly structured for a page-level story.


253-419: Excellent story coverage!

The story variants provide comprehensive coverage of page states, including edge cases like logged-out users and minimal user profiles. The variety helps ensure the UI handles different scenarios gracefully.


5-5: Install missing Storybook dependency.

Same issue as in SelectProject.stories.tsx - the @storybook/addon-actions package is not installed. See the fix recommended in that file.

⛔ Skipped due to learnings
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable references across renders
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable identities across renders

Comment on lines +12 to +14
function getAbsolutePath(value: string): any {
return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)))
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Return a concrete path type instead of any.

getAbsolutePath always resolves to a filesystem path, so returning any violates our “no any unless necessary” rule. Please give it a string return type to keep the config typed. As per coding guidelines.

-function getAbsolutePath(value: string): any {
+function getAbsolutePath(value: string): string {
   return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)))
 }
📝 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
function getAbsolutePath(value: string): any {
return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)))
}
function getAbsolutePath(value: string): string {
return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)))
}
🤖 Prompt for AI Agents
apps/web/client/.storybook/main.ts around lines 12 to 14: the helper
getAbsolutePath currently declares a return type of any even though it always
returns a filesystem path string; change the signature to return string (e.g.
function getAbsolutePath(value: string): string) and ensure any required
imports/types remain correct so callers receive a concrete string type instead
of any.

Comment on lines +82 to +95
define: {
'process.env': '{}',
'process': '{"env": {}}',
},
resolve: {
alias: {
'@/utils/supabase/client': fileURLToPath(
new URL('./mocks/supabase-client.ts', import.meta.url)
),
'@/trpc/react': fileURLToPath(
new URL('./mocks/trpc-react.tsx', import.meta.url)
),
'~/trpc/react': fileURLToPath(
new URL('./mocks/trpc-react.tsx', import.meta.url)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix the Vite define shim before it breaks env access.

Rewriting process.env/process to string literals leaves stories with a string instead of the expected object, so any access like process.env.STORYBOOK_THEME will silently return undefined. Storybook’s Vite guidance recommends using import.meta.env instead of faking process, so please remove these definitions (or replace them with the proper object form only if you truly must shim). (storybook.js.org)

-      define: {
-        'process.env': '{}',
-        'process': '{"env": {}}',
-      },
+      define: {
+        // rely on import.meta.env inside stories; no fake process shim
+      },
📝 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
define: {
'process.env': '{}',
'process': '{"env": {}}',
},
resolve: {
alias: {
'@/utils/supabase/client': fileURLToPath(
new URL('./mocks/supabase-client.ts', import.meta.url)
),
'@/trpc/react': fileURLToPath(
new URL('./mocks/trpc-react.tsx', import.meta.url)
),
'~/trpc/react': fileURLToPath(
new URL('./mocks/trpc-react.tsx', import.meta.url)
define: {
// rely on import.meta.env inside stories; no fake process shim
},
resolve: {
alias: {
'@/utils/supabase/client': fileURLToPath(
new URL('./mocks/supabase-client.ts', import.meta.url)
),
'@/trpc/react': fileURLToPath(
new URL('./mocks/trpc-react.tsx', import.meta.url)
),
'~/trpc/react': fileURLToPath(
new URL('./mocks/trpc-react.tsx', import.meta.url)
🤖 Prompt for AI Agents
In apps/web/client/.storybook/main.ts around lines 82 to 95, the Vite define
shim is overwriting process.env and process with string literals which breaks
environment variable access in stories; remove the define entries that set
'process.env' and 'process' (or replace them only with proper object shims if
absolutely required), and instead rely on import.meta.env for Storybook
environment variables per Vite/Storybook guidance so that accesses like
process.env.STORYBOOK_THEME continue to work (or update code to read
import.meta.env).

Comment on lines +1 to +5
{
"projectToken": "chpt_549eddb0e603baf",
"buildScriptName": "build-storybook",
"exitZeroOnChanges": true
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Chromatic project token exposed in repository.

The projectToken at line 2 is committed to the repository. While Chromatic project tokens are less sensitive than API keys with full access, exposing them allows anyone to:

  • Publish builds to your Chromatic project
  • Consume your Chromatic build quota
  • Potentially view your snapshots

Recommendation: Remove the token from this file and use the CHROMATIC_PROJECT_TOKEN environment variable instead:

 {
-  "projectToken": "chpt_549eddb0e603baf",
   "buildScriptName": "build-storybook",
   "exitZeroOnChanges": true
 }

Then set the token in your CI environment (GitHub Secrets) and pass it via the CLI or environment variable. The Chromatic CLI automatically picks up CHROMATIC_PROJECT_TOKEN from the environment.

Alternatively, if you want to keep it in the config for local development, use a local-only config file that's gitignored, and reference the environment variable in CI.

📝 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
{
"projectToken": "chpt_549eddb0e603baf",
"buildScriptName": "build-storybook",
"exitZeroOnChanges": true
}
{
"buildScriptName": "build-storybook",
"exitZeroOnChanges": true
}
🧰 Tools
🪛 Gitleaks (8.28.0)

[high] 2-2: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
In apps/web/client/chromatic.config.json around lines 1-5, the Chromatic
projectToken is committed; remove the "projectToken" entry from this file and
instead rely on the CHROMATIC_PROJECT_TOKEN environment variable in CI. Update
your CI workflow to add the token to secrets (e.g., GitHub Secrets) and pass it
to the Chromatic CLI or export CHROMATIC_PROJECT_TOKEN prior to running the
build; if local dev convenience is needed, create a separate gitignored local
config that contains the token and keep the repo version token-free.

Comment on lines +214 to +247
if (isLoading) {
return (
<div className="flex h-screen w-screen flex-col items-center justify-center">
<div className="flex flex-row items-center gap-2">
<Icons.LoadingSpinner className="text-foreground-primary h-6 w-6 animate-spin" />
<div className="text-foreground-secondary text-lg">Loading projects...</div>
</div>
</div>
);
}

if (projects.length === 0 && !debouncedSearchQuery) {
return (
<div className="flex h-full w-full flex-col items-center justify-center gap-4">
<div className="text-foreground-secondary text-xl">No projects found</div>
<div className="text-md text-foreground-tertiary">
Create a new project to get started
</div>
<div className="flex justify-center">
<Button
onClick={onCreateBlank}
disabled={isCreatingProject}
variant="default"
>
{isCreatingProject ? (
<Icons.LoadingSpinner className="h-4 w-4 animate-spin" />
) : (
<Icons.Plus className="h-4 w-4" />
)}
Create blank project
</Button>
</div>
</div>
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Localize the empty/loading states.

All of the user-facing strings in this view ("Loading projects...", "No projects found", "Create blank project", etc.) are hardcoded. Per our localization guideline for apps/web/client/src/app/**, please move them into next‑intl keys instead of embedding English text. As per coding guidelines.

-                    <Icons.LoadingSpinner className="text-foreground-primary h-6 w-6 animate-spin" />
-                    <div className="text-foreground-secondary text-lg">Loading projects...</div>
+                    <Icons.LoadingSpinner className="text-foreground-primary h-6 w-6 animate-spin" />
+                    <div className="text-foreground-secondary text-lg">
+                      {t(transKeys.projects.select.loading)}
+                    </div>

(repeat for the other messages in this block)

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

}}
className="gap-2 border border-gray-300 w-auto cursor-pointer bg-white text-black hover:bg-gray-100 px-4 py-2 rounded"
>
✏️ Edit
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Replace hardcoded text with next-intl messages.

The "Edit" text is hardcoded, but per coding guidelines for apps/web/client/src/**/*.tsx, user-facing text should use next-intl messages/hooks instead.

As per coding guidelines.

Apply this approach to internationalize the button text:

+import { useTranslations } from 'next-intl';
+
 export function SquareProjectCardPresentation({
     project,
     imageUrl,
     searchQuery = "",
     HighlightText,
     onClick,
 }: SquareProjectCardPresentationProps) {
+    const t = useTranslations('projects');
     const lastUpdated = useMemo(() => timeAgo(project.metadata.updatedAt), [project.metadata.updatedAt]);

Then update the button:

                         <button
                             onClick={(e) => {
                                 e.stopPropagation();
                                 handleClick();
                             }}
                             className="gap-2 border border-gray-300 w-auto cursor-pointer bg-white text-black hover:bg-gray-100 px-4 py-2 rounded"
                         >
-                            ✏️ Edit
+                            {t('edit')}
                         </button>
📝 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
✏️ Edit
import { useTranslations } from 'next-intl';
export function SquareProjectCardPresentation({
project,
imageUrl,
searchQuery = "",
HighlightText,
onClick,
}: SquareProjectCardPresentationProps) {
const t = useTranslations('projects');
const lastUpdated = useMemo(() => timeAgo(project.metadata.updatedAt), [project.metadata.updatedAt]);
// ... other code ...
<button
onClick={(e) => {
e.stopPropagation();
handleClick();
}}
className="gap-2 border border-gray-300 w-auto cursor-pointer bg-white text-black hover:bg-gray-100 px-4 py-2 rounded"
>
{t('edit')}
</button>

externalSearchQuery: '',
isCreatingProject: false,
onCreateBlank,
starredTemplateIds: new Set([templateProjects[0].id]),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix TypeScript error: Object is possibly 'undefined'.

TypeScript doesn't know that templateProjects[0] exists. Add optional chaining or a type assertion.

Apply this diff:

-    starredTemplateIds: new Set([templateProjects[0].id]),
+    starredTemplateIds: new Set([templateProjects[0]?.id].filter(Boolean) as string[]),
📝 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
starredTemplateIds: new Set([templateProjects[0].id]),
starredTemplateIds: new Set([templateProjects[0]?.id].filter(Boolean) as string[]),
🧰 Tools
🪛 GitHub Actions: CI

[error] 221-221: Object is possibly 'undefined'.

🤖 Prompt for AI Agents
In apps/web/client/src/stories/SelectProject.stories.tsx around line 221,
TypeScript complains "Object is possibly 'undefined'" for
templateProjects[0].id; update the expression to guard against undefined by
using optional chaining (templateProjects[0]?.id) or a non-null assertion/type
assertion (templateProjects[0]!.id or (templateProjects[0] as
TemplateProject).id) so the Set is constructed with a defined id without
TypeScript error, and handle the potential undefined case if needed (e.g.,
defaulting or conditional creation).

Copy link

@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: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37217c0 and 3bacaa6.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • apps/web/client/package.json (4 hunks)
  • apps/web/client/src/stories/ProjectsPage.stories.tsx (1 hunks)
  • apps/web/client/src/stories/SelectProject.stories.tsx (1 hunks)
  • apps/web/client/src/stories/TopBar.stories.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
apps/web/client/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/SelectProject.stories.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
apps/web/client/src/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain

apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'

Files:

  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/SelectProject.stories.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not use the any type unless necessary

Files:

  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/SelectProject.stories.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
{apps,packages}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Avoid using the any type unless absolutely necessary

Files:

  • apps/web/client/src/stories/TopBar.stories.tsx
  • apps/web/client/src/stories/SelectProject.stories.tsx
  • apps/web/client/src/stories/ProjectsPage.stories.tsx
🧠 Learnings (2)
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Use Bun for all installs and scripts; do not introduce npm, yarn, or pnpm

Applied to files:

  • apps/web/client/package.json
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Use Bun for all installs and scripts; do not use npm, yarn, or pnpm

Applied to files:

  • apps/web/client/package.json
🧬 Code graph analysis (3)
apps/web/client/src/stories/TopBar.stories.tsx (1)
apps/web/client/src/app/projects/_components/top-bar-presentation.tsx (1)
  • TopBarPresentation (45-191)
apps/web/client/src/stories/SelectProject.stories.tsx (1)
apps/web/client/src/app/projects/_components/select-presentation.tsx (1)
  • SelectProjectPresentation (72-532)
apps/web/client/src/stories/ProjectsPage.stories.tsx (2)
apps/web/client/src/app/projects/_components/top-bar-presentation.tsx (1)
  • TopBarPresentation (45-191)
apps/web/client/src/app/projects/_components/select-presentation.tsx (1)
  • SelectProjectPresentation (72-532)
🔇 Additional comments (4)
apps/web/client/package.json (2)

60-60: Verify @storybook/test placement.

@storybook/test is listed as a production dependency (line 60). Verify this is intentional. If tests are development-only, move it to devDependencies for clarity.


29-32: Storybook, Chromatic, and testing tooling integration looks good.

The new scripts and devDependencies are appropriate and well-versioned for a Storybook v10 / Vitest / Playwright / Chromatic setup. ESLint plugin integration aligns with the broader PR changes. Versions are consistent and modern.

Also applies to: 120-147

apps/web/client/src/stories/TopBar.stories.tsx (1)

1-58: LGTM! Past import issue resolved.

The file correctly uses fn from @storybook/test (line 4) and defines action callbacks at module level (lines 56-58), which is the proper pattern for Storybook 9+. The story structure and mock data are well-organized.

apps/web/client/src/stories/SelectProject.stories.tsx (1)

1-209: LGTM! Storybook 9 migration and TypeScript safety addressed.

The file correctly uses fn from @storybook/test and defines all action callbacks at module level (lines 197-209). The past TypeScript errors regarding undefined array access have been properly resolved using conditional checks and optional chaining throughout the story definitions.

"preview:standalone": "bun run build:standalone && bun run start:standalone",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"preview-storybook": "bun --bun x serve storybook-static -p 6007",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add missing serve package dependency.

The preview-storybook script runs bun --bun x serve storybook-static, but the serve package is not listed in devDependencies. This will fail at runtime with a package-not-found error.

Apply this diff to add the serve package and simplify the bun syntax to align with idiomatic usage:

     "scripts": {
         ...
-        "preview-storybook": "bun --bun x serve storybook-static -p 6007",
+        "preview-storybook": "bunx serve storybook-static -p 6007",
     },
     "devDependencies": {
+        "serve": "^14.2.0",
📝 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
"preview-storybook": "bun --bun x serve storybook-static -p 6007",
"scripts": {
...
"preview-storybook": "bunx serve storybook-static -p 6007",
...
},
...
"devDependencies": {
...
"serve": "^14.2.0",
...
}
🤖 Prompt for AI Agents
In apps/web/client/package.json around line 31, the preview-storybook script
uses `bun --bun x serve ...` and `serve` is missing from devDependencies; update
package.json by adding `"serve"` to devDependencies (with an appropriate
version) and simplify the script to use idiomatic Bun invocation, e.g. change
the script to `"preview-storybook": "bun x serve storybook-static -p 6007"`.

Comment on lines +25 to +60
return (
<div className="w-screen h-screen flex flex-col">
<TopBarPresentation
user={user}
searchQuery={searchQuery}
onSearchChange={setSearchQuery}
recentSearches={['dashboard', 'admin', 'portfolio']}
isCreatingProject={isCreatingProject}
onCreateBlank={fn()}
onImport={fn()}
homeRoute="/"
/>
<div className="flex justify-center w-full h-full overflow-y-auto overflow-x-visible">
<SelectProjectPresentation
allProjects={projects}
isLoading={isLoading}
externalSearchQuery={searchQuery}
isCreatingProject={isCreatingProject}
onCreateBlank={fn()}
starredTemplateIds={new Set()}
onToggleStar={fn()}
onUnmarkTemplate={fn()}
onRefetch={fn()}
onProjectClick={fn()}
onRenameProject={fn()}
onCloneProject={fn()}
onToggleTemplate={fn()}
onDeleteProject={fn()}
onUseTemplate={fn()}
onPreviewTemplate={fn()}
onEditTemplate={fn()}
user={user}
/>
</div>
</div>
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Hoist action handlers to module level.

Creating new fn() instances on every render (lines 33-34, 43-55) causes unnecessary re-renders and prevents Storybook from properly tracking actions. Follow the pattern used in TopBar.stories.tsx and SelectProject.stories.tsx by defining actions once at module level.

Apply this refactor:

+// Action callbacks (define at module level)
+const onCreateBlank = fn();
+const onImport = fn();
+const onToggleStar = fn();
+const onUnmarkTemplate = fn();
+const onRefetch = fn();
+const onProjectClick = fn();
+const onRenameProject = fn();
+const onCloneProject = fn();
+const onToggleTemplate = fn();
+const onDeleteProject = fn();
+const onUseTemplate = fn();
+const onPreviewTemplate = fn();
+const onEditTemplate = fn();
+
 const ProjectsPageComposed = ({
   user,
   projects,
   isLoading,
   isCreatingProject,
 }: {
   user?: User | null;
   projects: Project[];
   isLoading: boolean;
   isCreatingProject: boolean;
 }) => {
   const [searchQuery, setSearchQuery] = useState('');

   return (
     <div className="w-screen h-screen flex flex-col">
       <TopBarPresentation
         user={user}
         searchQuery={searchQuery}
         onSearchChange={setSearchQuery}
         recentSearches={['dashboard', 'admin', 'portfolio']}
         isCreatingProject={isCreatingProject}
-        onCreateBlank={fn()}
+        onCreateBlank={onCreateBlank}
-        onImport={fn()}
+        onImport={onImport}
         homeRoute="/"
       />
       <div className="flex justify-center w-full h-full overflow-y-auto overflow-x-visible">
         <SelectProjectPresentation
           allProjects={projects}
           isLoading={isLoading}
           externalSearchQuery={searchQuery}
           isCreatingProject={isCreatingProject}
-          onCreateBlank={fn()}
+          onCreateBlank={onCreateBlank}
-          starredTemplateIds={new Set()}
-          onToggleStar={fn()}
+          starredTemplateIds={new Set()}
+          onToggleStar={onToggleStar}
-          onUnmarkTemplate={fn()}
+          onUnmarkTemplate={onUnmarkTemplate}
-          onRefetch={fn()}
+          onRefetch={onRefetch}
-          onProjectClick={fn()}
+          onProjectClick={onProjectClick}
-          onRenameProject={fn()}
+          onRenameProject={onRenameProject}
-          onCloneProject={fn()}
+          onCloneProject={onCloneProject}
-          onToggleTemplate={fn()}
+          onToggleTemplate={onToggleTemplate}
-          onDeleteProject={fn()}
+          onDeleteProject={onDeleteProject}
-          onUseTemplate={fn()}
+          onUseTemplate={onUseTemplate}
-          onPreviewTemplate={fn()}
+          onPreviewTemplate={onPreviewTemplate}
-          onEditTemplate={fn()}
+          onEditTemplate={onEditTemplate}
           user={user}
         />
       </div>
     </div>
   );
 };
📝 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
return (
<div className="w-screen h-screen flex flex-col">
<TopBarPresentation
user={user}
searchQuery={searchQuery}
onSearchChange={setSearchQuery}
recentSearches={['dashboard', 'admin', 'portfolio']}
isCreatingProject={isCreatingProject}
onCreateBlank={fn()}
onImport={fn()}
homeRoute="/"
/>
<div className="flex justify-center w-full h-full overflow-y-auto overflow-x-visible">
<SelectProjectPresentation
allProjects={projects}
isLoading={isLoading}
externalSearchQuery={searchQuery}
isCreatingProject={isCreatingProject}
onCreateBlank={fn()}
starredTemplateIds={new Set()}
onToggleStar={fn()}
onUnmarkTemplate={fn()}
onRefetch={fn()}
onProjectClick={fn()}
onRenameProject={fn()}
onCloneProject={fn()}
onToggleTemplate={fn()}
onDeleteProject={fn()}
onUseTemplate={fn()}
onPreviewTemplate={fn()}
onEditTemplate={fn()}
user={user}
/>
</div>
</div>
);
// Action callbacks (define at module level)
const onCreateBlank = fn();
const onImport = fn();
const onToggleStar = fn();
const onUnmarkTemplate = fn();
const onRefetch = fn();
const onProjectClick = fn();
const onRenameProject = fn();
const onCloneProject = fn();
const onToggleTemplate = fn();
const onDeleteProject = fn();
const onUseTemplate = fn();
const onPreviewTemplate = fn();
const onEditTemplate = fn();
const ProjectsPageComposed = ({
user,
projects,
isLoading,
isCreatingProject,
}: {
user?: User | null;
projects: Project[];
isLoading: boolean;
isCreatingProject: boolean;
}) => {
const [searchQuery, setSearchQuery] = useState('');
return (
<div className="w-screen h-screen flex flex-col">
<TopBarPresentation
user={user}
searchQuery={searchQuery}
onSearchChange={setSearchQuery}
recentSearches={['dashboard', 'admin', 'portfolio']}
isCreatingProject={isCreatingProject}
onCreateBlank={onCreateBlank}
onImport={onImport}
homeRoute="/"
/>
<div className="flex justify-center w-full h-full overflow-y-auto overflow-x-visible">
<SelectProjectPresentation
allProjects={projects}
isLoading={isLoading}
externalSearchQuery={searchQuery}
isCreatingProject={isCreatingProject}
onCreateBlank={onCreateBlank}
starredTemplateIds={new Set()}
onToggleStar={onToggleStar}
onUnmarkTemplate={onUnmarkTemplate}
onRefetch={onRefetch}
onProjectClick={onProjectClick}
onRenameProject={onRenameProject}
onCloneProject={onCloneProject}
onToggleTemplate={onToggleTemplate}
onDeleteProject={onDeleteProject}
onUseTemplate={onUseTemplate}
onPreviewTemplate={onPreviewTemplate}
onEditTemplate={onEditTemplate}
user={user}
/>
</div>
</div>
);
};
🤖 Prompt for AI Agents
In apps/web/client/src/stories/ProjectsPage.stories.tsx around lines 25 to 60,
the story creates new fn() action handlers inline (e.g., onCreateBlank,
onImport, onToggleStar, onRefetch, onProjectClick, etc.), which causes
unnecessary re-renders and breaks Storybook action tracking; fix by declaring
each action once at module scope (const onCreateBlank = fn(); const onImport =
fn(); const onToggleStar = fn(); ...), then replace the inline fn() calls in the
JSX with these module‑level constants so the same function instance is used
across renders.

@vercel vercel bot temporarily deployed to Preview – docs November 6, 2025 00:36 Inactive
@saddlepaddle saddlepaddle changed the title Set up storybook and chromatic to test with onbook" Set up storybook and chromatic to test with onbook Nov 6, 2025
@saddlepaddle saddlepaddle merged commit fe8d89d into main Nov 6, 2025
7 of 8 checks passed
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.

2 participants