-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Set up storybook and chromatic to test with onbook #3038
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
| {label} | ||
| <style jsx>{` | ||
| button { | ||
| background-color: ${backgroundColor}; |
There was a problem hiding this comment.
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.
| 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> |
There was a problem hiding this comment.
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.
| <p>Edit App</p> | |
| <p>Edit Project</p> |
| alt="A book" | ||
| className="sb-explore-image" | ||
| /> | ||
| <p>Follow guided walkthroughs on for key workflows.</p> |
There was a problem hiding this comment.
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."
| <p>Follow guided walkthroughs on for key workflows.</p> | |
| <p>Follow guided walkthroughs for key workflows.</p> |
There was a problem hiding this 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.logandstorybook-static) are appropriate ignores for build artifacts and logs, but they're placed under the# mastrasection. 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/,/buildon 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-staticapps/web/client/src/stories/Configure.mdx (1)
221-280: Update deprecated Next.js Imagelayoutprop.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}andheight={32}, simply remove thelayout="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-labelfor 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_DESCRIPTIONconstant at line 54 limits reusability. Consider making it a prop. Additionally, thehandleEditwrapper is redundant since you can useonClick={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
showDescriptioninstead ofSHOW_DESCRIPTIONandonClick={() => onEdit?.(project)}instead ofonClick={handleEdit}.apps/web/client/src/stories/ProjectCard.stories.tsx (2)
1-41: Consider using ProjectCardPresentation for more isolated stories.While using the stateful
ProjectCardcomponent works, you might get more predictable and faster-rendering stories by usingProjectCardPresentation(if available) since it removes theuseEffectfor image loading and all side effects. This would make stories more deterministic and easier to test.If
ProjectCardPresentationexists, you could import it instead:import { ProjectCardPresentation } from '@/app/projects/_components/select/project-card-presentation';Then pass pre-resolved image URLs as the
imageUrlprop 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
@latestcan introduce unexpected breaking changes in CI. Pin to a specific version for reproducible builds.Apply this diff:
- uses: chromaui/action@latest + uses: chromaui/action@v13apps/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
createMockProjecthelper and mock project arrays are duplicated between this file andProjectsPage.stories.tsx. Consider extracting them to a shared module likeapps/web/client/src/stories/mocks/projects.tsfor 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
createMockProjecthelper,mockProjects, andtemplateProjectsarrays are duplicated fromSelectProject.stories.tsx. ThemockUserobject should also be shared. See the refactoring suggestion inSelectProject.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
⛔ Files ignored due to path filters (16)
apps/web/client/src/stories/assets/accessibility.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/accessibility.svgis excluded by!**/*.svgapps/web/client/src/stories/assets/addon-library.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/assets.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/context.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/discord.svgis excluded by!**/*.svgapps/web/client/src/stories/assets/docs.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/figma-plugin.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/github.svgis excluded by!**/*.svgapps/web/client/src/stories/assets/share.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/styling.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/testing.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/theming.pngis excluded by!**/*.pngapps/web/client/src/stories/assets/tutorials.svgis excluded by!**/*.svgapps/web/client/src/stories/assets/youtube.svgis excluded by!**/*.svgbun.lockis 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 insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsxapps/web/client/src/app/projects/_components/select-presentation.tsxapps/web/client/src/app/projects/_components/top-bar-presentation.tsxapps/web/client/src/app/projects/_components/select/project-card-presentation.tsxapps/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 insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/projects/_components/templates/template-modal-presentation.tsxapps/web/client/src/app/projects/_components/select-presentation.tsxapps/web/client/src/app/projects/_components/top-bar-presentation.tsxapps/web/client/src/stories/Page.tsxapps/web/client/src/stories/Header.stories.tsapps/web/client/src/stories/ProjectCard.stories.tsxapps/web/client/src/stories/TopBar.stories.tsxapps/web/client/src/stories/Button.stories.tsxapps/web/client/src/stories/Button.tsxapps/web/client/src/app/projects/_components/select/project-card-presentation.tsxapps/web/client/src/stories/ProjectsPage.stories.tsxapps/web/client/src/stories/Button.stories.tsapps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsxapps/web/client/src/stories/Header.tsxapps/web/client/src/stories/Page.stories.tsapps/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.tsxapps/web/client/src/app/projects/_components/select-presentation.tsxapps/web/client/src/app/projects/_components/top-bar-presentation.tsxapps/web/client/src/stories/Page.tsxapps/web/client/src/stories/ProjectCard.stories.tsxapps/web/client/src/stories/TopBar.stories.tsxapps/web/client/src/stories/Button.stories.tsxapps/web/client/src/stories/Button.tsxapps/web/client/src/app/projects/_components/select/project-card-presentation.tsxapps/web/client/src/stories/ProjectsPage.stories.tsxapps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsxapps/web/client/src/stories/Header.tsxapps/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.tsxapps/web/client/vitest.config.tsapps/web/client/src/app/projects/_components/select-presentation.tsxapps/web/client/src/app/projects/_components/top-bar-presentation.tsxapps/web/client/src/stories/Page.tsxapps/web/client/src/stories/Header.stories.tsapps/web/client/src/stories/ProjectCard.stories.tsxapps/web/client/src/stories/TopBar.stories.tsxapps/web/client/src/stories/Button.stories.tsxapps/web/client/src/stories/Button.tsxapps/web/client/vitest.shims.d.tsapps/web/client/src/app/projects/_components/select/project-card-presentation.tsxapps/web/client/src/stories/ProjectsPage.stories.tsxapps/web/client/src/stories/Button.stories.tsapps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsxapps/web/client/src/stories/Header.tsxapps/web/client/src/stories/Page.stories.tsapps/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.tsxapps/web/client/src/app/projects/_components/select-presentation.tsxapps/web/client/src/app/projects/_components/top-bar-presentation.tsxapps/web/client/src/app/projects/_components/select/project-card-presentation.tsxapps/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.tsxapps/web/client/vitest.config.tsapps/web/client/src/app/projects/_components/select-presentation.tsxapps/web/client/src/app/projects/_components/top-bar-presentation.tsxapps/web/client/src/stories/Page.tsxapps/web/client/src/stories/Header.stories.tsapps/web/client/src/stories/ProjectCard.stories.tsxapps/web/client/src/stories/TopBar.stories.tsxapps/web/client/src/stories/Button.stories.tsxapps/web/client/src/stories/Button.tsxapps/web/client/vitest.shims.d.tsapps/web/client/src/app/projects/_components/select/project-card-presentation.tsxapps/web/client/src/stories/ProjectsPage.stories.tsxapps/web/client/src/stories/Button.stories.tsapps/web/client/src/app/projects/_components/select/square-project-card-presentation.tsxapps/web/client/src/stories/Header.tsxapps/web/client/src/stories/Page.stories.tsapps/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.tsapps/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.tsxapps/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.tsxapps/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.tsxapps/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
HighlightTextfor 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-playwrightdependency 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"andenableSystemenabled. WhenforcedThemeis set, it overrides system preferences, makingenableSystemineffective.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.testto'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 6006build-storybook: Production buildpreview-storybook: Preview built Storybookchromatic: Chromatic integration with--exit-zero-on-changesflagAll scripts use Bun as per project guidelines.
119-145: I'll verify the dependency versions using an alternative approach sincebunis 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.jsonand usinguseTranslations('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/hooksLearnt 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 insteadLearnt 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 textLearnt 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 usetype: '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
anytypes, usingRecord<string, any>for mock router types is appropriate here. This prevents importing the real AppRouter and its dependencies, which would trigger thedotenv.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
ProjectsPageComposedcomponent 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-actionspackage 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 rendersLearnt 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
| function getAbsolutePath(value: string): any { | ||
| return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`))) | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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).
| { | ||
| "projectToken": "chpt_549eddb0e603baf", | ||
| "buildScriptName": "build-storybook", | ||
| "exitZeroOnChanges": true | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| { | |
| "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.
| 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> | ||
| ); |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| ✏️ 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]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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).
There was a problem hiding this 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
⛔ Files ignored due to path filters (1)
bun.lockis 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 insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/stories/TopBar.stories.tsxapps/web/client/src/stories/SelectProject.stories.tsxapps/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.tsxapps/web/client/src/stories/SelectProject.stories.tsxapps/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.tsxapps/web/client/src/stories/SelectProject.stories.tsxapps/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.tsxapps/web/client/src/stories/SelectProject.stories.tsxapps/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/testplacement.
@storybook/testis 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
fnfrom@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
fnfrom@storybook/testand 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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| "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"`.
| 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> | ||
| ); |
There was a problem hiding this comment.
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.
| 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.
Description
Related Issues
Type of Change
Testing
Screenshots (if applicable)
Additional Notes
Important
Set up Storybook and Chromatic for visual testing and component documentation with Next.js and Vite integration.
.storybook/main.tsfor Next.js and Vite.chromatic.ymlfor visual regression testing.mocks/trpc-react.tsxfor Storybook testing.SelectProjectPresentationandTopBarPresentation.stories/directory, includingButton.stories.tsandProjectsPage.stories.tsx.package.json.devDependencieswith Storybook and Chromatic packages.This description was created by
for 01ce483. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
New Features
Chores