Skip to content

Conversation

@NoritakaIkeda
Copy link
Member

@NoritakaIkeda NoritakaIkeda commented Oct 23, 2025

Issue

Why is this change needed?

This redesign improves the user experience of the project creation flow by introducing a clear step-based navigation system and better component organization. The previous implementation lacked visual guidance for users going through the multi-step process of creating a project.

GitHub Unauthenticated GitHub App Installation Not Specified GitHub App Installer Available
スクリーンショット 2025-10-27 15 47 36 スクリーンショット 2025-10-27 16 00 25 スクリーンショット 2025-10-27 16 01 40

Not Done Yet

  • Import Git Repository screen design: The styling for the repository list and other UI elements hasn’t been applied yet. For this update, only the minimal layout adjustments were made to match the current changes. The full design will be handled in a separate issue.
  • Set Watch Schemas screen implementation: This screen hasn’t been implemented yet—it doesn’t exist at all at this point.

Design Review Notes

  • Added a button for installing the GitHub App next to the installer selection field. This wasn’t defined in the original Figma design, but users need to be able to select or add a GitHub App installer at any time, even after one has already been selected.
  • Designed an empty state for cases where the token is valid but no installer has been configured yet.

Key Improvements:

  1. Step-based Navigation: Added a visual step indicator showing users their progress (Step 1: Import Git Repository, Step 2: Set Watch Schemas)

  2. Component Refactoring: Split the monolithic InstallationSelector into smaller, focused sub-components:

    • EmptyStateCard: Handles empty states (no installations, needs reauth)
    • HeaderActions: Manages installation selection and GitHub app connection
    • RepositoryList: Displays and handles repository selection
    • InstallationDropdown: Dedicated dropdown for installation selection
  3. Improved Visual Design:

    • Added JackAndOctcat illustration for empty states
    • Consistent use of CSS variables from @liam-hq/ui
    • Better spacing and layout with responsive design
    • Back navigation link to projects page
  4. Better State Management:

    • Enhanced error handling
    • Clearer loading states
    • Improved prop naming (changed disabled to needsRefresh for clarity)
  5. Code Quality:

    • Better separation of concerns
    • More maintainable component structure
    • Improved type safety with proper TypeScript usage

Summary by CodeRabbit

Release Notes

  • New Features

    • Added multi-step progress indicator to project creation flow
    • Redesigned installation and repository selection interface with improved visual hierarchy
    • Added back navigation to return to projects page
    • Introduced empty state cards with GitHub App installation prompts
  • Style

    • Enhanced layout and spacing for better visual organization
    • Added loading skeleton states for repository lists
    • Improved responsive design for project setup page

Redesigned the project new page to improve user experience with a clearer step-based navigation system and better component organization.

Key changes:
- Added step indicator showing current progress in project creation flow
- Refactored InstallationSelector into smaller, focused sub-components (EmptyStateCard, HeaderActions, RepositoryList, InstallationDropdown)
- Added JackAndOctcat illustration component for empty states
- Improved styling consistency using CSS variables from @liam-hq/ui
- Enhanced error handling and loading states
- Added back navigation link to projects page

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@giselles-ai
Copy link

giselles-ai bot commented Oct 23, 2025

Finished running flow.

Step Status Updated(UTC)
1 Oct 23, 2025 11:33pm
2 Oct 23, 2025 11:35pm
3 Oct 23, 2025 11:35pm

@vercel
Copy link

vercel bot commented Oct 23, 2025

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

Project Deployment Preview Comments Updated (UTC)
liam-app Ready Ready Preview Comment Oct 28, 2025 4:44am
liam-assets Ready Ready Preview Comment Oct 28, 2025 4:44am
liam-docs Ready Ready Preview Comment Oct 28, 2025 4:44am
liam-erd-sample Ready Ready Preview Oct 28, 2025 4:44am
liam-storybook Ready Ready Preview Comment Oct 28, 2025 4:44am

@supabase
Copy link

supabase bot commented Oct 23, 2025

Updates to Preview Branch (feat/project-new-page-redesign) ↗︎

Deployments Status Updated
Database Tue, 28 Oct 2025 04:41:26 UTC
Services Tue, 28 Oct 2025 04:41:26 UTC
APIs Tue, 28 Oct 2025 04:41:26 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Tue, 28 Oct 2025 04:41:28 UTC
Migrations Tue, 28 Oct 2025 04:41:28 UTC
Seeding Tue, 28 Oct 2025 04:41:28 UTC
Edge Functions Tue, 28 Oct 2025 04:41:28 UTC

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 23, 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

This PR refactors the ProjectNewPage's project creation flow, replacing a dropdown-based InstallationSelector with a section-based UI featuring dedicated components for installation selection, empty states, repository listing, and a multi-step progress header with updated styling.

Changes

Cohort / File(s) Change Summary
ProjectNewPage layout and styling
ProjectNewPage.module.css
Restructured layout with centered alignment, responsive padding, multi-step header styling (step, stepActive, stepBadge, stepLabel, stepDivider), and fixed line-height; replaced simple padding with gap-based content container
ProjectNewPage component
ProjectNewPage.tsx
Updated UI structure with multi-step header ("Add New Project"), two-step progression, Back to Projects link with ArrowLeft icon, and changed InstallationSelector prop from disabled to needsRefresh
InstallationSelector refactor
InstallationSelector.module.css, InstallationSelector.tsx
Replaced dropdown-driven layout with section-based panel design; class changes (.container, .panel, .panelContent); component rewrite with needsRefresh prop, EmptyStateVariant logic, and HeaderActions + RepositoryList composition
New UI components—EmptyStateCard
EmptyStateCard/EmptyStateCard.module.css, EmptyStateCard/EmptyStateCard.tsx, EmptyStateCard/EmptyStateCard.stories.tsx
New empty-state component displaying illustration, description, and action button with disabled/loading states; includes Storybook stories for NoInstallations, NoRepositories, and Disabled variants
New UI component—JackAndOctcat illustration
EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx, EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx, EmptyStateCard/JackAndOctcat/index.ts
New SVG illustration component with filters and accessibility attributes; includes Storybook story
New UI components—HeaderActions
HeaderActions/HeaderActions.module.css, HeaderActions/HeaderActions.tsx, HeaderActions/HeaderActions.stories.tsx, HeaderActions/index.ts
Header section rendering installation dropdown and "Configure Repositories on GitHub" button; includes Storybook stories for Default and Disabled states
New UI components—InstallationDropdown
InstallationDropdown/InstallationDropdown.module.css, InstallationDropdown/InstallationDropdown.tsx, InstallationDropdown/InstallationDropdown.stories.tsx, InstallationDropdown/index.ts
Dropdown selector for GitHub installations with login display and selection callback; includes five Storybook stories demonstrating different states
New UI components—RepositoryList
RepositoryList/RepositoryList.module.css, RepositoryList/RepositoryList.tsx, RepositoryList/index.ts
List renderer for repositories with titled section; conditionally renders based on installation selection and error state
New UI component—RepositoryListSkeleton
RepositoryListSkeleton/RepositoryListSkeleton.module.css, RepositoryListSkeleton/RepositoryListSkeleton.tsx, RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx, RepositoryListSkeleton/index.ts
Skeleton loader with pulsing animation for six placeholder items; includes Storybook story
EmptyStateCard and JackAndOctcat barrel exports
EmptyStateCard/index.ts, JackAndOctcat/index.ts
Barrel export files exposing EmptyStateCard and JackAndOctcat modules
Supporting updates
ProjectSessionsPage.module.css, ProjectsPage/NoProjects/index.ts
Increased max-width in ProjectSessionsPage from 400px to 444px; added re-export of JackAndOctcat from NoProjects index
Icon exports
frontend/packages/ui/src/icons/index.ts, frontend/packages/ui/src/icons/index.stories.tsx
Added ArrowLeft icon export from lucide-react and included in Storybook icon showcase

Sequence Diagram

sequenceDiagram
    participant User
    participant ProjectNewPage
    participant InstallationSelector
    participant HeaderActions
    participant InstallationDropdown
    participant EmptyStateCard
    participant RepositoryList

    User->>ProjectNewPage: Load project creation page
    ProjectNewPage->>InstallationSelector: Render with needsRefresh prop
    
    alt No installations or needs reauth
        InstallationSelector->>EmptyStateCard: Render empty state
        User->>EmptyStateCard: Click action button
        EmptyStateCard->>InstallationSelector: onActionClick callback
    else Has installations
        InstallationSelector->>HeaderActions: Render
        HeaderActions->>InstallationDropdown: Render with installations
        User->>InstallationDropdown: Select installation
        InstallationDropdown->>InstallationSelector: onSelect(installation)
        InstallationSelector->>RepositoryList: Fetch & render repositories
        RepositoryList-->>InstallationSelector: Show repository list
        User->>RepositoryList: Select repository
    end
    
    note over InstallationSelector: If loading or no selection<br/>show RepositoryListSkeleton
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Key areas requiring attention:
    • InstallationSelector.tsx refactor: substantial logic changes around prop handling (disabled → needsRefresh), component composition, state management (selectedInstallation sync), and data flow for add-project operations
    • New EmptyStateVariant enum logic and conditional rendering branches
    • HeaderActions and InstallationDropdown integration with form submission flow
    • Multiple new components with CSS modules and Storybook stories (consistent patterns, but each requires validation)
    • Installation selection and repository listing synchronization logic

Possibly related PRs

Suggested labels

Review effort 4/5

Suggested reviewers

  • sasamuku
  • MH4GF
  • junkisai

Poem

🐰 A project born takes steps anew,
From simple forms to flows so true! ✨
Jack and Octcat hop and cheer,
Installation dances crystal clear,
Repositories align with grace,
The UI finds its proper place! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "✨(app): Redesign project creation page with step-based navigation" accurately reflects the primary change in the changeset. The summary shows extensive refactoring of the ProjectNewPage component to introduce step-based navigation, accompanied by significant component restructuring (InstallationSelector split into EmptyStateCard, HeaderActions, InstallationDropdown, RepositoryList, and RepositoryListSkeleton) and visual improvements. The title is concise, clear, and specific enough that a teammate scanning history would immediately understand the main objective: redesigning the project creation flow with step indicators.
Description Check ✅ Passed The PR description fully complies with the required template structure. It includes the "Issue" section with a resolved GitHub issue link and the "Why is this change needed?" section with a clear explanation of the improvements (step-based navigation, component organization, and better UX guidance). Beyond meeting template requirements, the description provides substantial additional context: screenshots of three different installation states, design review notes explaining deviations from the original Figma design, a detailed list of key improvements, and a "Not Done Yet" section transparently communicating incomplete work.
✨ 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 feat/project-new-page-redesign

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.

@giselles-ai
Copy link

giselles-ai bot commented Oct 23, 2025

Check changeset necessity

Status: NOT REQUIRED

Reason:

  • All changes are within @liam-hq/app (frontend/apps/app), which is in the ignore list for changesets.
  • No modifications to target publishable packages: @liam-hq/cli, @liam-hq/erd-core, @liam-hq/schema, or @liam-hq/ui.
  • Although user-facing (UI redesign, step-based navigation), the impact is limited to the app and not to a published package.
  • No API, feature, or bug-fix changes were made to any versioned packages; only app-level components, CSS, and internal structure were updated.

Changeset (copy & paste):

N/A – no changeset needed (app-only changes).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css (1)

32-90: Consider using px directly for flex-basis.

Line 78 uses a spacing variable for flex-basis:

flex: 0 0 var(--spacing-25, 100px);

According to the coding guidelines, spacing CSS variables should be used only for margins and padding, not for width/height dimensions. While flex-basis is not exactly width, it serves a similar purpose.

Consider this refactor for consistency with the guidelines:

-.stepDivider {
-  flex: 0 0 var(--spacing-25, 100px);
+.stepDivider {
+  flex: 0 0 100px;
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx (1)

52-74: Consider filtering installations before mapping.

The current implementation maps all installations and returns null for those without a valid login. This could be optimized and made more defensive by filtering first:

-      <DropdownMenuContent className={styles.dropdownContent}>
-        {installations.map((installation) => {
-          const login = match(installation.account)
-            .with({ login: P.string }, (account) => account.login)
-            .otherwise(() => null)
-
-          if (login === null) return null
-
-          return (
-            <DropdownMenuItem
-              key={installation.id}
-              onSelect={() => onSelect(installation)}
-              leftIcon={
-                <GithubLogo
-                  className={styles.menuItemIcon}
-                  aria-hidden
-                  focusable="false"
-                />
-              }
-            >
-              {login}
-            </DropdownMenuItem>
-          )
-        })}
+      <DropdownMenuContent className={styles.dropdownContent}>
+        {installations
+          .map((installation) => ({
+            installation,
+            login: match(installation.account)
+              .with({ login: P.string }, (account) => account.login)
+              .otherwise(() => null),
+          }))
+          .filter(({ login }) => login !== null)
+          .map(({ installation, login }) => (
+            <DropdownMenuItem
+              key={installation.id}
+              onSelect={() => onSelect(installation)}
+              leftIcon={
+                <GithubLogo
+                  className={styles.menuItemIcon}
+                  aria-hidden
+                  focusable="false"
+                />
+              }
+            >
+              {login}
+            </DropdownMenuItem>
+          ))}
       </DropdownMenuContent>

This approach:

  • Eliminates scattered return null statements
  • Makes the logic clearer by explicitly filtering invalid entries
  • Slightly better performance (no React key generation for null returns)
frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx (1)

48-48: Consider removing redundant Boolean() conversion.

Since needsRefresh is already typed as boolean | undefined, the Boolean() wrapper is redundant. You can pass it directly:

-        needsRefresh={Boolean(needsRefresh)}
+        needsRefresh={needsRefresh ?? false}

Or rely on the default value in InstallationSelector (which already defaults to false):

-        needsRefresh={Boolean(needsRefresh)}
+        needsRefresh={needsRefresh}
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (1)

70-92: Consider capturing project creation errors with Sentry.

Line 87 uses console.error for error handling, but since Sentry is already integrated (imported on line 4), project creation failures should be captured for monitoring and debugging.

         } catch (error) {
-          console.error('Error adding project:', error)
+          Sentry.captureException(error, {
+            tags: { action: 'add_project' },
+            extra: { repositoryName: repository.name },
+          })
         }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 470cea7 and 4664e3a.

📒 Files selected for processing (15)
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx (2 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (4 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx (1 hunks)
  • frontend/apps/app/components/ProjectSessionsPage/ProjectSessionsPage.module.css (1 hunks)
  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/JackAndOctcat.tsx (1 hunks)
  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.module.css

📄 CodeRabbit inference engine (AGENTS.md)

Use CSS Modules named *.module.css and keep types via typed-css-modules

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.module.css
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
  • frontend/apps/app/components/ProjectSessionsPage/ProjectSessionsPage.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.module.css
frontend/apps/**

📄 CodeRabbit inference engine (AGENTS.md)

Next.js apps live under frontend/apps; target app-specific scripts and configs there

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.module.css
  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
  • frontend/apps/app/components/ProjectSessionsPage/ProjectSessionsPage.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.module.css
  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
frontend/**/*.{css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for all styling

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.module.css
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
  • frontend/apps/app/components/ProjectSessionsPage/ProjectSessionsPage.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.module.css
frontend/**/*.{module.css,module.scss}

📄 CodeRabbit inference engine (CLAUDE.md)

frontend/**/*.{module.css,module.scss}: Use CSS Variables from the @liam-hq/ui package in styles
Use spacing CSS variables only for margins and padding; use size units (rem, px, etc.) for height/width

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.module.css
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
  • frontend/apps/app/components/ProjectSessionsPage/ProjectSessionsPage.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.module.css
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Name React component files in PascalCase and use TSX (e.g., App.tsx)

Files:

  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript/TSX across the codebase

Files:

  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

frontend/**/*.{ts,tsx}: Use named exports only (no default exports)
Import UI components from @liam-hq/ui when available
Import icons from @liam-hq/ui
Follow existing import patterns and tsconfig path aliases
Use consts instead of function declarations for simple utilities (e.g., const toggle = () => {})
Use runtime type validation with valibot for external data validation
Use early returns for readability

Files:

  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name utility files in camelCase (e.g., mergeSchema.ts)

Files:

  • frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/index.ts
🧬 Code graph analysis (6)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx (3)
frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/JackAndOctcat.tsx (1)
  • JackAndOctcat (5-196)
frontend/packages/ui/src/components/Button/Button.tsx (1)
  • Button (23-80)
frontend/packages/ui/src/logos/GithubLogo.tsx (1)
  • GithubLogo (5-24)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (4)
frontend/internal-packages/github/src/types.ts (1)
  • Installation (3-3)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (1)
  • HeaderActions (18-72)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx (1)
  • EmptyStateCard (15-42)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx (1)
  • RepositoryList (14-50)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx (3)
frontend/internal-packages/github/src/types.ts (1)
  • Installation (3-3)
frontend/packages/ui/src/components/Button/Button.tsx (1)
  • Button (23-80)
frontend/packages/ui/src/logos/GithubLogo.tsx (1)
  • GithubLogo (5-24)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx (1)
frontend/internal-packages/github/src/types.ts (1)
  • Repository (4-4)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (5)
frontend/internal-packages/github/src/types.ts (1)
  • Installation (3-3)
frontend/packages/ui/src/components/Button/Button.tsx (1)
  • Button (23-80)
frontend/packages/ui/src/logos/GithubLogo.tsx (1)
  • GithubLogo (5-24)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx (1)
  • InstallationDropdown (22-78)
frontend/packages/ui/src/icons/index.ts (1)
  • Plus (55-55)
frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx (2)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (1)
  • InstallationSelector (28-148)
frontend/packages/ui/src/icons/index.ts (2)
  • Link (41-41)
  • ChevronLeft (12-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: frontend-ci
  • GitHub Check: frontend-lint
  • GitHub Check: Supabase Preview
  • GitHub Check: security-review
  • GitHub Check: codeql / languages (javascript) / Perform CodeQL for javascript
🔇 Additional comments (20)
frontend/apps/app/components/ProjectSessionsPage/ProjectSessionsPage.module.css (1)

77-77: LGTM — straightforward width adjustment for empty state description.

The change appropriately increases max-width to accommodate longer description text. The use of px units aligns with your coding guidelines (size units for max-width) and is consistent with other fixed widths in the file (e.g., width: 782px on line 12).

As a nice-to-have improvement, consider whether this (and other fixed px values in the file) would benefit from rem units for better scalability across different zoom levels and DPI settings. This is not blocking—just an optional consideration for future refactoring.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.module.css (1)

1-25: LGTM!

The CSS module follows the coding guidelines correctly:

  • Uses CSS variables from @liam-hq/ui with appropriate fallbacks
  • Spacing variables are used for margins, padding, and gaps (as per guidelines)
  • Fixed dimensions (width/height) use px units directly (allowed per guidelines)
  • Layout is well-structured with flexbox
frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/JackAndOctcat.tsx (1)

1-196: LGTM!

This SVG illustration component is well-implemented:

  • Uses useId() to generate SSR-safe unique IDs for SVG filters, preventing ID collisions
  • Properly typed with ComponentPropsWithoutRef<'svg'> to accept standard SVG props
  • Includes accessibility attributes (role="img", aria-label)
  • Follows naming conventions (PascalCase component, named export)
frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/index.ts (1)

2-4: LGTM!

Standard barrel exports for the new illustration components.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (2)

28-47: Verify button text for the no-installations scenario.

The button text logic may be confusing for first-time users:

const actionText = needsRefresh ? 'Continue with GitHub' : 'Add Installation'
if (!hasInstallations || needsRefresh) {
  // renders button with actionText
}

When hasInstallations is false and needsRefresh is false, the button displays "Add Installation". This might be semantically unclear for first-time setup—"Add" typically implies adding to an existing collection. Consider whether "Connect with GitHub" or "Get Started with GitHub" would be clearer in this scenario.

Alternatively, if this is intentional, the logic could be made more explicit:

const actionText = needsRefresh 
  ? 'Continue with GitHub' 
  : hasInstallations 
    ? 'Add Installation' 
    : 'Connect with GitHub'

52-71: LGTM!

The dropdown + install button layout is well-structured. The disabled states correctly gate both the dropdown and the install button based on needsRefresh and githubAppUrl availability.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.module.css (1)

1-28: LGTM!

CSS module correctly uses CSS variables from @liam-hq/ui and follows the coding guidelines. Spacing variables are appropriately used for gaps and padding.

frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css (2)

1-30: LGTM!

The container and content layout styling is well-structured with proper use of CSS variables for spacing, font, and colors.


92-109: LGTM!

The back link styling is well-implemented with proper hover states and uses CSS variables correctly for colors, spacing, and sizing.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.module.css (1)

1-20: LGTM!

The empty state styling follows the coding guidelines correctly:

  • Spacing variables used appropriately for gap
  • Fixed dimensions (width/height) use px units as allowed
  • CSS variables from @liam-hq/ui used for colors and font sizing
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx (1)

22-78: LGTM overall!

The component is well-structured with proper TypeScript typing, accessibility attributes on icons, and correct use of the ts-pattern library for type-safe matching. The disabled state is properly handled throughout.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx (1)

1-50: LGTM! Well-structured component with clear separation of concerns.

The component correctly handles error states, empty states, and repository rendering. The conditional messaging based on hasSelectedInstallation provides good UX feedback. Implementation follows coding guidelines with named exports and early returns.

frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx (2)

25-44: LGTM! Clean multi-step header implementation.

The step-based navigation provides clear visual guidance for the project creation flow. The hardcoded active state for Step 1 is appropriate for the current implementation scope.


50-53: LGTM! Proper navigation implementation.

The back link correctly uses Next.js Link with appropriate aria attributes for the decorative icon.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx (1)

15-41: LGTM! Clean empty state implementation.

The component provides clear user guidance with appropriate illustrations and CTAs. The conditional text and button labels adapt well to the connect vs reauth variants.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.module.css (1)

13-19: Verify that the fixed height doesn't cause overflow or responsiveness issues.

The panelContent class uses a fixed height of 610px, which could lead to overflow if the repository list or error messages exceed this height, or wasted space if content is minimal. Consider whether this should use min-height instead to allow for dynamic content sizing.

If the fixed height is intentional for consistent UI layout across states, please ensure that the content within this panel is scrollable when it exceeds the fixed height.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.module.css (1)

1-31: LGTM! Well-structured dropdown styles.

The CSS module correctly uses spacing variables for padding and gaps, with appropriate fixed dimensions for icons and min-widths for the dropdown components. The flex layout properties ensure proper spacing and alignment.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (3)

45-52: LGTM! Handler separation supports future OAuth implementation.

While handleConnectGitHub currently just wraps handleInstallApp, this separation is appropriate given the TODO comment in EmptyStateCard.tsx (line 10) indicating that re-authentication will eventually use a different OAuth flow.


54-68: LGTM! Proper guard against actions during refresh.

The early return when needsRefresh is true correctly prevents installation selection during re-authentication flows. The nested transitions properly manage the loading states.


113-147: LGTM! Well-structured component composition.

The refactored structure clearly separates concerns with HeaderActions, EmptyStateCard, and RepositoryList components. The conditional rendering logic correctly handles loading, empty states, and repository display.

Refactored GitHub App URL handling to use a boolean flag instead of passing the full URL string, improving component interface clarity and reducing prop drilling.

Changes:
- Changed githubAppUrl prop to hasGithubAppUrl boolean in HeaderActions
- Removed Sentry error logging for missing env var (not needed at component level)
- Removed default value for actionDisabled prop in EmptyStateCard

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@NoritakaIkeda
Copy link
Member Author

NoritakaIkeda commented Oct 23, 2025

@junkisai
I’d appreciate it if you could take a look at the next phase as well, since there’s a lot of design implementation involved 🙏

I think we can refine and adjust this a bit more from a UI perspective, so I'll move it to Draft for now. Sorry about that. 🙏

@NoritakaIkeda NoritakaIkeda marked this pull request as ready for review October 23, 2025 23:54
@NoritakaIkeda NoritakaIkeda requested a review from a team as a code owner October 23, 2025 23:54
@NoritakaIkeda NoritakaIkeda requested review from MH4GF, Copilot, junkisai and sasamuku and removed request for a team October 23, 2025 23:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR redesigns the project creation page by introducing a step-based navigation system and refactoring the installation selector into smaller, focused components. The redesign enhances user experience with visual progress indicators, improved empty states with illustrations, and better separation of concerns in the component architecture.

Key Changes:

  • Implemented a two-step progress indicator (Import Git Repository → Set Watch Schemas) with visual badges and active state highlighting
  • Refactored the monolithic InstallationSelector into four sub-components for better maintainability
  • Added JackAndOctcat illustration component for empty states to improve visual feedback

Reviewed Changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ProjectNewPage.tsx Added step-based header with progress indicators and back navigation link
ProjectNewPage.module.css Comprehensive styling for the new layout with step indicators, header, and navigation elements
InstallationSelector.tsx Major refactoring to use sub-components and improved state management with needsRefresh prop
InstallationSelector.module.css Updated to panel-based layout with fixed height container
EmptyStateCard.tsx New component handling empty states for connect/reauth scenarios
HeaderActions.tsx New component managing installation selection dropdown and GitHub app connection buttons
InstallationDropdown.tsx Extracted dropdown component for installation selection
RepositoryList.tsx New component for displaying and managing repository selection
JackAndOctcat.tsx SVG illustration component for empty states
EmptyProjectsState/index.ts Added exports for new illustration components
ProjectSessionsPage.module.css Minor adjustment to max-width value

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

const formData = new FormData()
formData.append('installationId', installation.id.toString())
repositoriesAction(formData)
const hasInstallations = installations.length > 0
Copy link

Copilot AI Oct 23, 2025

Choose a reason for hiding this comment

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

[nitpick] The hasInstallations variable is computed on every render but could be memoized with useMemo to avoid unnecessary recalculations, especially if the installations array is large or the component re-renders frequently.

Copilot uses AI. Check for mistakes.
Comment on lines 93 to 97
const emptyStateVariant: EmptyStateVariant | null = needsRefresh
? 'reauth'
: hasInstallations
? null
: 'connect'
Copy link

Copilot AI Oct 23, 2025

Choose a reason for hiding this comment

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

[nitpick] The emptyStateVariant computation could be memoized with useMemo since it depends on needsRefresh and hasInstallations. This would prevent unnecessary recalculations on every render.

Suggested change
const emptyStateVariant: EmptyStateVariant | null = needsRefresh
? 'reauth'
: hasInstallations
? null
: 'connect'
const emptyStateVariant: EmptyStateVariant | null = useMemo(() => {
if (needsRefresh) return 'reauth';
if (hasInstallations) return null;
return 'connect';
}, [needsRefresh, hasInstallations]);

Copilot uses AI. Check for mistakes.
Comment on lines +99 to +103
const dropdownLabel = selectedInstallation
? match(selectedInstallation.account)
.with({ login: P.string }, (item) => item.login)
.otherwise(() => 'Select installation')
: 'Select installation'
Copy link

Copilot AI Oct 23, 2025

Choose a reason for hiding this comment

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

[nitpick] The dropdownLabel computation could be memoized with useMemo to avoid re-running the pattern match on every render when selectedInstallation hasn't changed.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (2)

42-42: Consider memoization for performance.

This computation is recalculated on every render. While the cost is minimal, memoization would prevent unnecessary recalculations when installations hasn't changed.


93-103: Consider memoization for performance.

Both emptyStateVariant and dropdownLabel are recomputed on every render. Memoizing them would prevent unnecessary recalculations.

Apply this diff:

+  const emptyStateVariant: EmptyStateVariant | null = useMemo(() => {
+    if (needsRefresh) return 'reauth'
+    if (hasInstallations) return null
+    return 'connect'
+  }, [needsRefresh, hasInstallations])
+
+  const dropdownLabel = useMemo(() => {
+    if (!selectedInstallation) return 'Select installation'
+    return match(selectedInstallation.account)
+      .with({ login: P.string }, (item) => item.login)
+      .otherwise(() => 'Select installation')
+  }, [selectedInstallation])
-  const emptyStateVariant: EmptyStateVariant | null = needsRefresh
-    ? 'reauth'
-    : hasInstallations
-      ? null
-      : 'connect'
-
-  const dropdownLabel = selectedInstallation
-    ? match(selectedInstallation.account)
-        .with({ login: P.string }, (item) => item.login)
-        .otherwise(() => 'Select installation')
-    : 'Select installation'

Don't forget to import useMemo from React.

🧹 Nitpick comments (2)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (1)

49-51: Consider removing the redundant wrapper.

handleConnectGitHub simply wraps handleInstallApp without adding any functionality. You can use handleInstallApp directly in the component render (lines 114, 125) to reduce indirection.

Apply this diff to simplify:

-  const handleConnectGitHub = useCallback(() => {
-    handleInstallApp()
-  }, [handleInstallApp])
-
   const handleSelectInstallation = useCallback(

Then update the usage sites (lines 114, 125):

-        onConnectGitHub={handleConnectGitHub}
+        onConnectGitHub={handleInstallApp}
-              onActionClick={handleConnectGitHub}
+              onActionClick={handleInstallApp}
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (1)

28-28: Consider extracting action text to a helper constant.

The inline ternary for actionText is recomputed on every render. While the cost is minimal, extracting it to a small helper or using useMemo would improve clarity and follow the pattern of separating data computation from render logic.

Apply this diff:

+const getActionText = (needsRefresh: boolean) =>
+  needsRefresh ? 'Continue with GitHub' : 'Add Installation'
+
 export const HeaderActions: FC<HeaderActionsProps> = ({
   hasInstallations,
   needsRefresh,
   ...
 }) => {
-  const actionText = needsRefresh ? 'Continue with GitHub' : 'Add Installation'
+  const actionText = getActionText(needsRefresh)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4664e3a and a1278d8.

📒 Files selected for processing (3)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (3 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Name React component files in PascalCase and use TSX (e.g., App.tsx)

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript/TSX across the codebase

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
frontend/apps/**

📄 CodeRabbit inference engine (AGENTS.md)

Next.js apps live under frontend/apps; target app-specific scripts and configs there

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

frontend/**/*.{ts,tsx}: Use named exports only (no default exports)
Import UI components from @liam-hq/ui when available
Import icons from @liam-hq/ui
Follow existing import patterns and tsconfig path aliases
Use consts instead of function declarations for simple utilities (e.g., const toggle = () => {})
Use runtime type validation with valibot for external data validation
Use early returns for readability

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx
🧬 Code graph analysis (2)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (5)
frontend/internal-packages/github/src/types.ts (1)
  • Installation (3-3)
frontend/packages/ui/src/components/Button/Button.tsx (1)
  • Button (23-80)
frontend/packages/ui/src/logos/GithubLogo.tsx (1)
  • GithubLogo (5-24)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown.tsx (1)
  • InstallationDropdown (22-78)
frontend/packages/ui/src/icons/index.ts (1)
  • Plus (55-55)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (4)
frontend/internal-packages/github/src/types.ts (1)
  • Installation (3-3)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (1)
  • HeaderActions (18-72)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard.tsx (1)
  • EmptyStateCard (15-42)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList.tsx (1)
  • RepositoryList (14-50)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Supabase Preview
  • GitHub Check: Supabase Preview
  • GitHub Check: Supabase Preview
🔇 Additional comments (8)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (4)

14-16: LGTM!

The new component imports follow the coding guidelines for named exports and proper module organization.


22-22: LGTM!

The prop rename from disabled to needsRefresh improves semantic clarity and better describes the authentication state.


53-67: Clarify the nested transitions pattern.

The nested startTransition (line 58) wrapping startAddingProjectTransition (line 59) is unusual. Typically, you'd use a single transition for async state updates.

The outer startTransition at line 35 appears to be declared but its purpose in this nesting isn't clear. Consider simplifying to a single transition unless there's a specific reason for the two-level nesting.

If the nested transitions serve distinct purposes (e.g., different loading states), consider adding a comment explaining the pattern. Otherwise, simplify to:

   const handleSelectInstallation = useCallback(
     (installation: Installation) => {
       if (needsRefresh) return

       setSelectedInstallation(installation)
-      startTransition(() => {
-        startAddingProjectTransition(() => {
-          const formData = new FormData()
-          formData.append('installationId', installation.id.toString())
-          repositoriesAction(formData)
-        })
-      })
+      startAddingProjectTransition(() => {
+        const formData = new FormData()
+        formData.append('installationId', installation.id.toString())
+        repositoriesAction(formData)
+      })
     },
     [needsRefresh, repositoriesAction],
   )

105-140: LGTM!

The refactored rendering structure with HeaderActions, EmptyStateCard, and RepositoryList components provides clean separation of concerns and improves maintainability. The conditional rendering logic correctly handles loading, empty, and list states.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions.tsx (4)

1-6: LGTM!

Imports follow the coding guidelines: using named exports, importing UI components from @liam-hq/ui, and proper module organization.


7-16: LGTM!

The props type definition is clear and well-structured. All props are appropriately typed and named.


29-50: LGTM!

The conditional logic correctly handles both the "no installations" and "needs refresh" states by presenting a single action button. The button is appropriately disabled when the GitHub App URL is unavailable, and the icon includes proper accessibility attributes.


52-72: LGTM!

The default state correctly renders the installation dropdown and install button. Both elements properly handle the disabled state when needsRefresh is true or when the GitHub App URL is unavailable. Accessibility attributes are correctly applied to icons.

@NoritakaIkeda NoritakaIkeda marked this pull request as draft October 24, 2025 01:49
…nent structure

- Move component files into dedicated RepositoryListSkeleton directory
- Add Storybook stories for visual testing
- Add index.ts for clean imports
- Maintain same component structure and styling
…ucture

- Move RepositoryList component files to directory-based structure
- Relocate RepositoryItem as a child component under RepositoryList
- Add index.ts export file for RepositoryList
- Maintain component encapsulation by nesting related components
…cture

- Move HeaderActions.tsx and .module.css into HeaderActions/ directory
- Add index.ts for clean exports
- Add Storybook stories for component documentation
- Generate CSS type definitions
- Maintain existing component behavior and props interface

This follows the project's directory-based component pattern for better organization.
…nt structure

- Move InstallationDropdown.tsx to InstallationDropdown/index.tsx
- Move InstallationDropdown.module.css to InstallationDropdown/ directory
- Maintain consistent component organization pattern with other recent refactorings
Copy link
Member

@junkisai junkisai left a comment

Choose a reason for hiding this comment

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

Thank you for the implementation!
I have a few comments.

Also, I've created a PR to manage components on a directory basis and add Storybook files, targeting this branch.
Please feel free to incorporate it if you'd like. 🙏
#3904

Import Git Repository
</span>
</div>
<span className={styles.stepDivider} aria-hidden="true" />
Copy link
Member

@junkisai junkisai Oct 28, 2025

Choose a reason for hiding this comment

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

📝 I want to prepare the StepArrow component.(I'll create it in a separate PR!)

Image

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you so much🙏

@vercel vercel bot temporarily deployed to Preview – liam-erd-sample October 28, 2025 03:12 Inactive
Change gap from var(--spacing-4) to var(--spacing-7) for better visual spacing in the project creation page header.

Co-authored-by: Junki Saito <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 650903f and 2079f78.

📒 Files selected for processing (1)
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.module.css

📄 CodeRabbit inference engine (AGENTS.md)

Use CSS Modules named *.module.css and keep types via typed-css-modules

Files:

  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
frontend/apps/**

📄 CodeRabbit inference engine (AGENTS.md)

Next.js apps live under frontend/apps; target app-specific scripts and configs there

Files:

  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
frontend/**/*.{css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for all styling

Files:

  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
frontend/**/*.{module.css,module.scss}

📄 CodeRabbit inference engine (CLAUDE.md)

frontend/**/*.{module.css,module.scss}: Use CSS Variables from the @liam-hq/ui package in styles
Use spacing CSS variables only for margins and padding; use size units (rem, px, etc.) for height/width

Files:

  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Supabase Preview
  • GitHub Check: Supabase Preview
  • GitHub Check: frontend-ci
  • GitHub Check: frontend-lint
  • GitHub Check: codeql / languages (javascript) / Perform CodeQL for javascript
  • GitHub Check: Supabase Preview

Comment on lines +54 to +55
width: var(--spacing-6, 24px);
height: var(--spacing-6, 24px);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use size units for width/height instead of spacing variables.

Per coding guidelines, spacing CSS variables should only be used for margins and padding. Width and height properties should use explicit size units (px, rem, etc.).

Apply this diff:

 .stepBadge {
   display: flex;
   align-items: center;
   justify-content: center;
-  width: var(--spacing-6, 24px);
-  height: var(--spacing-6, 24px);
+  width: 24px;
+  height: 24px;
   border-radius: var(--border-radius-full, 9999px);
📝 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
width: var(--spacing-6, 24px);
height: var(--spacing-6, 24px);
width: 24px;
height: 24px;
🤖 Prompt for AI Agents
frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css lines
54-55: width and height are using spacing variables; update them to explicit
size units instead (e.g., replace width: var(--spacing-6, 24px); and height:
var(--spacing-6, 24px); with explicit values like width: 24px; and height: 24px;
or the project’s preferred size variables/units) so width/height do not rely on
spacing CSS vars.

}

.stepDivider {
flex: 0 0 var(--spacing-25, 100px);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use size units for flex-basis instead of spacing variables.

Flex-basis is a size property and should use explicit units rather than spacing variables.

Apply this diff:

 .stepDivider {
-  flex: 0 0 var(--spacing-25, 100px);
+  flex: 0 0 100px;
   height: 1px;
📝 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
flex: 0 0 var(--spacing-25, 100px);
.stepDivider {
flex: 0 0 100px;
height: 1px;
}
🤖 Prompt for AI Agents
In frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css around
line 79, the flex-basis uses a spacing variable (var(--spacing-25, 100px)) which
is a spacing token rather than an explicit size; update the declaration so
flex-basis is an explicit size value (e.g., use a px/rem value like 100px or
switch to a dedicated size token such as var(--size-25, 100px)) instead of the
spacing variable.

Comment on lines +108 to +109
width: var(--spacing-4, 16px);
height: var(--spacing-4, 16px);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use size units for width/height instead of spacing variables.

Per coding guidelines, spacing CSS variables should only be used for margins and padding. Width and height properties should use explicit size units (px, rem, etc.).

Apply this diff:

 .backIcon {
-  width: var(--spacing-4, 16px);
-  height: var(--spacing-4, 16px);
+  width: 16px;
+  height: 16px;
 }
🤖 Prompt for AI Agents
In frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css around
lines 108 to 109, width and height currently use spacing CSS variables; replace
them with explicit size units per guidelines (e.g., use 16px or 1rem) so width
and height use concrete units instead of --spacing variables; update both
properties to the chosen unit and run a quick visual check to ensure layout
remains correct.

♻️(app): Refactor ProjectNewPage components to directory-based structure
@NoritakaIkeda
Copy link
Member Author

@junkisai #3904 Thanks for the PR! It looked really good, so I pulled it in. I plan to merge once the CI passes.

Copy link
Member

@junkisai junkisai left a comment

Choose a reason for hiding this comment

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

👍👍

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx (1)

21-24: Null return for empty/error states is already tracked.

This issue was flagged in a previous review and acknowledged by the developer for separate resolution.

🧹 Nitpick comments (5)
frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx (2)

50-53: Consider moving the back link to the top of the page.

The "Back to Projects" link is placed at the bottom of the content, which is unconventional for navigation. Users typically expect back/navigation links at the top of the page for easier access and better discoverability.

Apply this diff to move the back link to a more conventional position:

     <div className={styles.content}>
+      <Link href={urlgen('projects')} className={styles.backLink}>
+        <ArrowLeft aria-hidden className={styles.backIcon} />
+        <span>Back to Projects</span>
+      </Link>
       <header className={styles.header}>
         <h1 className={styles.title}>Add New Project</h1>

And remove it from the bottom:

         organizationId={organizationId}
         needsRefresh={needsRefresh}
       />
-      <Link href={urlgen('projects')} className={styles.backLink}>
-        <ArrowLeft aria-hidden className={styles.backIcon} />
-        <span>Back to Projects</span>
-      </Link>
     </div>

51-51: Consider specifying explicit size for the ArrowLeft icon.

For consistency with other icon usage in the codebase, consider adding an explicit size attribute to the ArrowLeft icon.

Apply this diff:

-        <ArrowLeft aria-hidden className={styles.backIcon} />
+        <ArrowLeft aria-hidden className={styles.backIcon} size={16} />
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx (2)

30-34: Redundant disabled prop on both DropdownMenuTrigger and Button.

The disabled prop is set on both the DropdownMenuTrigger (line 30) and the nested Button (line 34). While this may be intentional for Radix UI compatibility, it creates redundancy that could be simplified if only one is necessary.

If only the Button's disabled state is sufficient, apply this diff:

-    <DropdownMenuRoot>
-      <DropdownMenuTrigger asChild disabled={disabled}>
+    <DropdownMenuRoot>
+      <DropdownMenuTrigger asChild>
         <Button
           size="md"
           variant="outline-secondary"
           disabled={disabled}

52-74: Add handling for filtered installations and empty states.

The component silently filters out installations without a string login (line 57), which could lead to confusion. Additionally, there's no handling for when all installations are filtered out, resulting in an empty dropdown with no user feedback.

Consider adding:

  1. Console warning when installations are filtered
  2. Empty state message when no valid installations remain
  3. Or validate installations at the parent level before passing them down

Example implementation:

     <DropdownMenuContent className={styles.dropdownContent}>
-      {installations.map((installation) => {
+      {installations.length === 0 ? (
+        <div className={styles.emptyState}>No installations available</div>
+      ) : (
+        installations.map((installation) => {
           const login = match(installation.account)
             .with({ login: P.string }, (account) => account.login)
             .otherwise(() => null)
 
-          if (login === null) return null
+          if (login === null) {
+            console.warn('Installation missing login:', installation.id)
+            return null
+          }
 
           return (
             <DropdownMenuItem
               key={installation.id}
               onSelect={() => onSelect(installation)}
               leftIcon={
                 <GithubLogo
                   className={styles.menuItemIcon}
                   aria-hidden
                   focusable="false"
                 />
               }
             >
               {login}
             </DropdownMenuItem>
           )
-        })}
+        })
+      )}
     </DropdownMenuContent>
frontend/apps/app/components/ProjectsPage/components/NoProjects/index.ts (1)

1-1: Consider moving shared illustration to a common location.

Re-exporting JackAndOctcat from ProjectNewPage into ProjectsPage creates tight coupling between these two page-level modules. If this illustration is used by both pages, consider moving it to a shared location (e.g., components/shared/ or components/illustrations/) to better reflect its reusable nature and avoid cross-page dependencies.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2079f78 and 50296b6.

📒 Files selected for processing (26)
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx (2 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.stories.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/index.ts (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/index.ts (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.stories.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/index.ts (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.stories.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/index.ts (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/index.ts (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.module.css (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.tsx (1 hunks)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/index.ts (1 hunks)
  • frontend/apps/app/components/ProjectsPage/components/NoProjects/index.ts (1 hunks)
  • frontend/packages/ui/src/icons/index.stories.tsx (2 hunks)
  • frontend/packages/ui/src/icons/index.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.module.css
🧰 Additional context used
📓 Path-based instructions (9)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name utility files in camelCase (e.g., mergeSchema.ts)

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/index.ts
  • frontend/packages/ui/src/icons/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/index.ts
  • frontend/apps/app/components/ProjectsPage/components/NoProjects/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript/TSX across the codebase

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/index.ts
  • frontend/packages/ui/src/icons/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/index.ts
  • frontend/packages/ui/src/icons/index.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx
  • frontend/apps/app/components/ProjectsPage/components/NoProjects/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/index.ts
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx
frontend/apps/**

📄 CodeRabbit inference engine (AGENTS.md)

Next.js apps live under frontend/apps; target app-specific scripts and configs there

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx
  • frontend/apps/app/components/ProjectsPage/components/NoProjects/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.module.css
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

frontend/**/*.{ts,tsx}: Use named exports only (no default exports)
Import UI components from @liam-hq/ui when available
Import icons from @liam-hq/ui
Follow existing import patterns and tsconfig path aliases
Use consts instead of function declarations for simple utilities (e.g., const toggle = () => {})
Use runtime type validation with valibot for external data validation
Use early returns for readability

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/index.ts
  • frontend/packages/ui/src/icons/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/index.ts
  • frontend/packages/ui/src/icons/index.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx
  • frontend/apps/app/components/ProjectsPage/components/NoProjects/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/index.ts
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/index.ts
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx
frontend/packages/**

📄 CodeRabbit inference engine (AGENTS.md)

Shared libraries and tools live under frontend/packages

Files:

  • frontend/packages/ui/src/icons/index.ts
  • frontend/packages/ui/src/icons/index.stories.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Name React component files in PascalCase and use TSX (e.g., App.tsx)

Files:

  • frontend/packages/ui/src/icons/index.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx
  • frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx
**/*.module.css

📄 CodeRabbit inference engine (AGENTS.md)

Use CSS Modules named *.module.css and keep types via typed-css-modules

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.module.css
frontend/**/*.{css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for all styling

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.module.css
frontend/**/*.{module.css,module.scss}

📄 CodeRabbit inference engine (CLAUDE.md)

frontend/**/*.{module.css,module.scss}: Use CSS Variables from the @liam-hq/ui package in styles
Use spacing CSS variables only for margins and padding; use size units (rem, px, etc.) for height/width

Files:

  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.module.css
  • frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.module.css
🧬 Code graph analysis (10)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx (2)
frontend/packages/ui/src/components/Button/Button.tsx (1)
  • Button (23-80)
frontend/packages/ui/src/icons/index.ts (1)
  • Plus (56-56)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx (3)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx (1)
  • JackAndOctcat (5-196)
frontend/packages/ui/src/components/Button/Button.tsx (1)
  • Button (23-80)
frontend/packages/ui/src/logos/GithubLogo.tsx (1)
  • GithubLogo (5-24)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx (4)
frontend/internal-packages/github/src/types.ts (1)
  • Installation (3-3)
frontend/packages/ui/src/components/Button/Button.tsx (1)
  • Button (23-80)
frontend/packages/ui/src/logos/GithubLogo.tsx (1)
  • GithubLogo (5-24)
frontend/packages/ui/src/icons/index.ts (1)
  • ChevronDown (12-12)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.stories.tsx (2)
frontend/internal-packages/github/src/types.ts (1)
  • Installation (3-3)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.tsx (1)
  • InstallationDropdown (22-78)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx (2)
frontend/internal-packages/github/src/types.ts (1)
  • Repository (4-4)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryItem/RepositoryItem.tsx (1)
  • RepositoryItem (11-29)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.stories.tsx (1)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx (1)
  • EmptyStateCard (14-35)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.stories.tsx (1)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx (1)
  • HeaderActions (11-31)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx (1)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.tsx (1)
  • RepositoryListSkeleton (9-21)
frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx (2)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.tsx (1)
  • InstallationSelector (30-204)
frontend/packages/ui/src/icons/index.ts (2)
  • Link (42-42)
  • ArrowLeft (4-4)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx (1)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx (1)
  • JackAndOctcat (5-196)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Supabase Preview
  • GitHub Check: frontend-lint
  • GitHub Check: frontend-ci
  • GitHub Check: Supabase Preview
🔇 Additional comments (30)
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.module.css (1)

1-18: Clean CSS implementation with proper use of design system tokens.

The CSS module correctly applies @liam-hq/ui design system variables throughout, with appropriate use of spacing variables for gaps, color variables for text styling, and font sizing variables. The fallback values are well-chosen, and the class structure is semantic and maintainable.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/index.ts (1)

1-1: LGTM!

Standard barrel export pattern that enables centralized imports for the RepositoryList module.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryList/RepositoryList.tsx (1)

1-40: Component structure and implementation look good.

The component follows coding guidelines with named exports, proper TypeScript typing, and clean React patterns. The repository mapping logic correctly uses repo.id as the key, and props are appropriately passed to child components.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.module.css (1)

1-37: LGTM! Clean skeleton loader styling.

The CSS module follows all coding guidelines correctly:

  • Uses CSS variables from @liam-hq/ui package with appropriate fallbacks
  • Applies spacing variables (--spacing-4, --spacing-3) for gaps as per guidelines
  • Uses fixed units (px) for height/width dimensions
  • Animation is smooth and appropriate for skeleton loading states
frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/index.ts (1)

1-1: LGTM! Standard barrel export.

Follows the named export pattern correctly and aligns with the project's module structure.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.stories.tsx (1)

1-21: LGTM! Well-structured Storybook story.

The story setup follows Storybook best practices with appropriate meta configuration, decorator for width constraint, and proper TypeScript typing with the satisfies operator.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/RepositoryListSkeleton/RepositoryListSkeleton.tsx (1)

9-21: LGTM! Clean skeleton component implementation.

The component is well-structured and follows all coding guidelines:

  • Uses named exports correctly
  • Proper TypeScript typing with FC
  • CSS Module integration
  • React best practices with key props in the map

The TODO comment about moving to a shared UI library is a good note for future consolidation and is appropriate to defer.

frontend/packages/ui/src/icons/index.ts (1)

4-4: LGTM!

The ArrowLeft icon export is correctly added and maintains alphabetical ordering.

frontend/packages/ui/src/icons/index.stories.tsx (1)

4-4: LGTM!

ArrowLeft is correctly integrated into the Storybook showcase, following the established pattern for other icons.

Also applies to: 88-88

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/index.ts (1)

1-1: LGTM!

Standard barrel export pattern consistent with project conventions.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.tsx (1)

5-31: LGTM!

The component is well-structured with clear prop types and proper accessibility handling for the decorative Plus icon.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/HeaderActions/HeaderActions.stories.tsx (1)

4-58: LGTM!

The Storybook stories provide appropriate coverage with well-documented controls and a clean mock component.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/index.ts (1)

1-1: LGTM!

Standard barrel export following project conventions.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.stories.tsx (5)

1-3: LGTM!

Imports follow the coding guidelines and use named imports appropriately.


5-146: Comprehensive mock data for testing.

The mock Installation objects are well-structured and cover multiple scenarios (Organization vs User accounts, different repository selections). This level of detail is excellent for visual testing in Storybook.


148-170: Well-configured Storybook meta.

The meta configuration is properly typed and includes helpful descriptions for all props, which aids documentation and developer experience.


172-172: Default export required by Storybook.

This default export is necessary for Storybook's file-based story configuration and is an acceptable exception to the "no default exports" guideline.


173-213: Excellent story coverage.

The five story variations thoroughly cover the component's key states and edge cases, providing a comprehensive visual test suite.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/InstallationDropdown/InstallationDropdown.module.css (6)

1-8: LGTM!

The .dropdownTrigger class correctly uses CSS variables from @liam-hq/ui with appropriate fallbacks. Spacing variables are properly used for padding and gap, while size units (px) are used for width as per coding guidelines.


10-12: LGTM!

Appropriate use of px units for minimum width.


14-18: LGTM!

Icon dimensions correctly use px units for width and height as specified in the coding guidelines.


20-22: LGTM!

Preventing label shrinkage with flex-shrink: 0 ensures consistent label display.


24-26: LGTM!

The spacer correctly uses flexbox to create flexible spacing within the dropdown trigger.


28-31: LGTM!

Dropdown icon dimensions follow the same correct sizing pattern as other icons in this module.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.tsx (2)

5-7: LGTM: Excellent use of useId for SSR-safe filter IDs.

Using React's useId hook to generate unique filter IDs ensures the SVG renders correctly when multiple instances exist on the page and during server-side rendering.


10-18: LGTM: Proper accessibility attributes.

The SVG includes appropriate accessibility attributes (role="img" and aria-label="Jack and Octocat") and correctly spreads props to allow className and other SVG attributes to be overridden.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.stories.tsx (1)

4-34: LGTM: Well-structured Storybook configuration.

The story configuration includes helpful argTypes documentation, a width-constraining decorator for consistent preview, and covers the main use cases (no installations, no repositories, and disabled state).

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/EmptyStateCard.tsx (2)

24-32: LGTM: Proper accessibility handling for decorative icon.

The GithubLogo icon correctly uses aria-hidden to hide it from screen readers (as it's decorative alongside the button text) and focusable="false" to prevent keyboard focus on the SVG element.


7-7: TODO comment is appropriate for future enhancement.

The TODO clearly documents the planned OAuth re-authentication handler. This is acceptable for tracking future work.

frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/components/EmptyStateCard/JackAndOctcat/JackAndOctcat.stories.tsx (1)

4-14: LGTM: Appropriate minimal story for illustration component.

For a pure SVG illustration component, a single Default story with centered layout is sufficient to enable visual inspection in Storybook.

@NoritakaIkeda NoritakaIkeda added this pull request to the merge queue Oct 28, 2025
Merged via the queue into main with commit 27f6a47 Oct 28, 2025
36 checks passed
@NoritakaIkeda NoritakaIkeda deleted the feat/project-new-page-redesign branch October 28, 2025 04:51
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.

4 participants