Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 53 additions & 27 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

```bash
# Development
npm run watch # Watch mode for development
npm run watch # Watch mode for development (Webpack watch)
npm run build # Production build
npm run build:pack # Build and create dist.zip package
npm run release # Build and package for release
npm run release # Build and create dist.zip for Chrome Web Store

# Testing and Quality
npm test # Run Jest tests
Expand All @@ -22,13 +21,21 @@ npm run clean # Clean dist directory
npm run prepare # Setup husky hooks

# Chrome Extension Development
# Load the 'dist' directory in Chrome's extension developer mode after building
# After building, load the 'dist' directory in Chrome's extension developer mode (chrome://extensions)
```

## Project Architecture

This is a Chrome extension (Manifest v3) that enhances GitHub and GitHub Enterprise UI with productivity features.

### Tech Stack

- **Frontend**: React 18 + TypeScript
- **Styling**: SASS Modules + Styled Components + Primer React
- **Build**: Webpack 5 with TypeScript and code splitting
- **Validation**: Yup schemas
- **API**: Octokit (GitHub), Axios (JIRA)

### Core Structure

- **Content Scripts**: Three separate content scripts inject functionality into different GitHub pages:
Expand All @@ -42,16 +49,17 @@ This is a Chrome extension (Manifest v3) that enhances GitHub and GitHub Enterpr
- `popup.tsx` - Extension popup interface
- `options.tsx` - Options/settings page with tabbed interface

### Key Components
### Settings Management

Settings are stored in Chrome storage API and validated using Yup schemas (`src/services/getSettings.ts`).

- **Settings Management**: Uses Chrome storage API with Yup schema validation (`src/services/getSettings.ts`)
- **Multi-Instance Support**: Supports multiple GitHub instances (Enterprise + GitHub.com) via instance configuration
- **Feature Toggles**: All features are individually toggleable via settings
- **JIRA Integration**: Fetches issue data through background script to bypass CORS
**Key Schema Features**:

### Settings Architecture
- `.cast()` is used instead of `.validate()` for graceful handling of invalid settings
- Supports both `chrome.storage.local` and `chrome.storage.sync` based on `persistToUserProfile` feature flag
- Settings gracefully fallback to defaults when invalid or missing

Settings are validated using Yup schemas and organized into:
**Settings Structure**:

- **`instances[]`** - GitHub instance configurations
- `pat` - Personal Access Token (must start with `ghp_`, minimum 30 characters)
Expand All @@ -71,6 +79,7 @@ Settings are validated using Yup schemas and organized into:
- `prTitleFromJira` - Auto-populate PR title from JIRA ticket
- `descriptionTemplate` - Use custom PR description template
- `randomReviewer` - Enable random reviewer assignment
- `persistToUserProfile` - Sync settings across devices using chrome.storage.sync

- **`jira{}`** - JIRA integration settings (optional)
- `pat` - JIRA Personal Access Token (minimum 30 characters)
Expand All @@ -79,24 +88,32 @@ Settings are validated using Yup schemas and organized into:

- **`autoFilter`** - Custom PR filtering query string (optional)
- **`descriptionTemplate`** - Custom PR description template text (optional)
- **`fileBlacklist`** - Comma-separated list of files to exclude from line counts (default: "package-lock.json,pnpm-lock.yaml,yarn.lock")

### Options Page Structure

The Options page uses a tabbed interface with the following tabs:
The Options page uses a tabbed interface (`src/pages/Tabs/`):

- **Feature Toggles** - Individual toggles for all extension features
- **GH Instances** - GitHub instance configuration (PAT, org, repo, base URL)
- **Jira** - JIRA integration settings
- **Import/Export** - Settings backup and restore functionality

Each tab is implemented as a separate component in `src/pages/Tabs/` with dedicated styling and logic.

### Build System

- **Webpack**: Multi-entry build with code splitting (vendor chunk for all except background)
- **SASS Modules**: CSS modules with local scope and hash-based class names
- **TypeScript**: Full TypeScript with strict validation
- **Entry Points**: Separate bundles for popup, options, content scripts, and background
**Webpack Configuration** (`webpack/webpack.common.js`):

- Multi-entry build with 6 entry points: popup, options, 3 content scripts, and background
- Code splitting: `vendor.js` shared by all bundles except background (service workers can't use shared chunks)
- SASS Modules with CSS Modules for scoped styles (pattern: `[name]_[local]__[hash:base64]`)
- TypeScript with ts-loader
- CopyPlugin to copy public assets to dist

**Important Build Notes**:

- Development mode uses `mode: 'production'` in `webpack.dev.js` to avoid a Primer React bug with development builds
- Source maps are generated in development via `devtool: 'inline-source-map'`
- Each content script loads `vendor.js` first, then the specific content script bundle

### Chrome Extension Permissions

Expand All @@ -107,12 +124,19 @@ Each tab is implemented as a separate component in `src/pages/Tabs/` with dedica
### Development Workflow

1. Run `npm run watch` for development
2. Load `dist` directory in Chrome extension developer mode
2. Load `dist` directory in Chrome's extension developer mode (`chrome://extensions`)
3. Changes auto-reload with webpack watch mode
4. Use `npm run clean` to clear dist before production builds
5. Run `npm test` to execute Jest unit tests
6. Use `npm run lint:fix` to automatically fix linting issues
7. Format code with `npm run prettier` before committing
4. Run `npm test` to execute Jest unit tests
5. Use `npm run lint:fix` to automatically fix linting issues
6. Format code with `npm run prettier` before committing
7. Pre-commit hooks (husky + lint-staged) ensure code quality

### Releasing to Chrome Web Store

1. Update version in `public/manifest.json`
2. Run `npm run release` to build and create `dist.zip`
3. Login to [Chrome Web Store Developer Dashboard](https://chrome.google.com/webstore/devconsole)
4. Upload the zip file and submit for review

## Coding Guidelines

Expand All @@ -122,14 +146,16 @@ Each tab is implemented as a separate component in `src/pages/Tabs/` with dedica
- **Component Structure**: Follow existing component folder structure with index.ts barrel exports
- **Type Safety**: Never use `any` type - use proper typing with `unknown` for uncertain types
- **Type Casting**: When type casting is necessary, always include safety checks before casting
- **Data Attributes**: Every component should have a unique `data-testid` resembling its component name
- **Component Size**: Write small, composable, reusable components

## Important Implementation Notes

- Settings validation uses Yup schemas with strict type checking
- Settings validation uses Yup `.cast()` (not `.validate()`) for graceful error handling
- GitHub API integration uses Octokit with user-provided PATs
- JIRA API calls must go through background script due to CORS
- JIRA API calls must go through background script due to CORS restrictions
- Features are conditionally loaded based on current page URL and user settings
- CSS modules prevent style conflicts with GitHub's native styles
- Pre-commit hooks with husky and lint-staged ensure code quality
- All settings are persisted to Chrome's local storage API
- All settings can be persisted to either chrome.storage.local or chrome.storage.sync
- The extension supports hot reloading during development via webpack watch mode
- Content scripts detect which GitHub page they're on via URL matching and conditionally inject features
3 changes: 3 additions & 0 deletions src/content/reOrderPrs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export async function reOrderPrs(
page: 1,
});

// If there are no PRs, return early
if (prs.length === 0) return;

// get the repo's default branch
const { default_branch } = prs[0].head.repo;

Expand Down