diff --git a/CLAUDE.md b/CLAUDE.md index 780e490e..6fc2a4d2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 @@ -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: @@ -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) @@ -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) @@ -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 @@ -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 @@ -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 diff --git a/src/content/reOrderPrs.ts b/src/content/reOrderPrs.ts index cab8b66e..ba3f5c75 100644 --- a/src/content/reOrderPrs.ts +++ b/src/content/reOrderPrs.ts @@ -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;