mirror of
https://github.com/yoshiko-pg/difit.git
synced 2026-09-19 05:03:24 +08:00
5f697599ba
* feat: Add revision selector to change base/target commits dynamically Add dropdown selectors to allow users to change the base and target revisions without restarting the server. Changes: - Add /api/revisions endpoint to fetch available branches and recent commits - Modify /api/diff to accept base/target query parameters - Add RevisionSelector component with optgroups (Special, Recent Commits, Branches) - Add revision state management in App.tsx with confirmation dialog for clearing comments - Handle working/staged constraints (working can only compare with staged) - Update test mocks to handle multiple API endpoints 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Resolve HEAD/HEAD^ to commit hashes for revision selector When starting without arguments (default HEAD), the revision selector was showing "All Uncommitted Changes" for both base and target because HEAD and HEAD^ values didn't exist in the dropdown options. Changes: - Add resolvedBase and resolvedTarget to getRevisionOptions() to resolve symbolic refs like HEAD/HEAD^ to actual commit hashes - Update /api/revisions to return resolved values - Use resolved values as initial selection in revision selector - This ensures the correct commits are selected on initial load Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * fix: Resolve symbolic refs in /api/diff response for revision selector The previous fix only resolved refs in /api/revisions, but /api/diff was still returning HEAD/HEAD^ which would overwrite the resolved values. Changes: - Add resolveCommitish() method to GitDiffParser - Resolve symbolic refs (HEAD, HEAD^, etc.) in /api/diff response - Use the new method in getRevisionOptions() to avoid duplication Now both /api/diff and /api/revisions return resolved commit hashes, ensuring the revision selector displays the correct values. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * fix: Use shortHash for select values to match resolved hashes The select options were using full commit hashes (commit.hash) as values, but the server was returning 7-character short hashes. This caused the selector to not match and default to the first option. Changes: - Change RevisionSelector to use commit.shortHash as option values - Remove debug logging Now the selector correctly matches the resolved short hashes returned from the server. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * feat: Sort branches with default branch first in revision selector Add getDefaultBranch() method to detect the repository's default branch (usually main or master) by checking origin/HEAD, and sort the branch list to show it first. Changes: - Add getDefaultBranch() method to GitDiffParser - Try to get default branch from origin/HEAD - Fall back to common defaults (main, master) if origin/HEAD not set - Sort branches in getRevisionOptions(): 1. Default branch (main/master) 2. Current branch 3. Others (alphabetically) This makes it easier to find the main branch in the selector. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * feat: Replace native select with custom dropdown for revision selector Replace the native select element with a custom dropdown that provides better visibility and UX: - Click or hover to open dropdown - Wider dropdown (320px min) with better spacing - Full commit messages visible (no truncation in dropdown) - Section headers for Special/Recent Commits/Branches - Selected item highlighted - Auto-closes on mouse leave or outside click - Uses ChevronDown icon for better affordance The custom dropdown provides much better readability compared to the native select, especially for long commit messages and branch names. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * feat: Improve revision selector with floating-ui and UX enhancements User request: Improve the revision selector in the header to prevent viewport overflow and enhance interaction. Implemented improvements: - Install @floating-ui/react dependency - Update RevisionSelector to use floating-ui for viewport-aware positioning with flip() and shift() middleware - Replace click interaction with hover/blur using useHover() and useFocus() hooks - Add safePolygon() to prevent dropdown from closing when moving mouse to dropdown - Reduce selector trigger width to half (max-w-[100px]) and prevent text wrapping - Set dropdown width to 360px - Allow commit messages to wrap in dropdown with break-words class - Set initial focus to current value when dropdown opens using getInitialFocusIndex() - Disable react-hooks/refs ESLint rule due to false positives with @floating-ui/react callback refs Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * fix: Remove commit message truncation in revision selector Remove the 50-character truncation of commit messages in the revision selector dropdown. Messages are now displayed in full and will wrap using the break-words CSS class applied in the frontend. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * fix: Make commit message font size consistent with other options Add text-xs class to commit hash and message to match the font size used in Special options and Branches sections. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * feat: Disable commits older than base in target selector Add disabledValues prop to RevisionSelector to support disabling multiple values. In the target revision selector, disable not only the base revision but also all commits older than the base revision to prevent selecting invalid revision ranges. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * refactor: Simplify disabled values by removing disabledValue prop Replace disabledValue prop with disabledValues array for consistency. This simplifies the implementation by using a single approach for disabling options in the revision selector. Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * unclear existing comments --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
import '@testing-library/jest-dom';
|
|
import { vi } from 'vitest';
|
|
import { Agent, setGlobalDispatcher } from 'undici';
|
|
|
|
// Disable keep-alive for tests to prevent ECONNRESET errors
|
|
// Use pipelining=0 instead of keepAlive=false for this version of undici
|
|
setGlobalDispatcher(new Agent({ pipelining: 0 }));
|
|
|
|
// Mock fetch globally for component tests, but not for server integration tests
|
|
if (!process.env.VITEST_SERVER_TEST) {
|
|
global.fetch = vi.fn();
|
|
}
|
|
|
|
// Mock console.error to suppress error logs during tests
|
|
global.console.error = vi.fn();
|
|
|
|
// Mock window.getComputedStyle
|
|
Object.defineProperty(window, 'getComputedStyle', {
|
|
value: () => ({
|
|
getPropertyValue: () => '',
|
|
}),
|
|
});
|
|
|
|
// Global test utilities
|
|
export const mockFetch = (response: any, revisionsResponse?: any) => {
|
|
(global.fetch as any).mockImplementation((url: string) => {
|
|
// Handle /api/revisions endpoint
|
|
if (url.includes('/api/revisions')) {
|
|
return Promise.resolve({
|
|
ok: revisionsResponse !== null,
|
|
json: async () =>
|
|
revisionsResponse ?? {
|
|
specialOptions: [],
|
|
branches: [],
|
|
commits: [],
|
|
},
|
|
});
|
|
}
|
|
// Default: /api/diff and others
|
|
return Promise.resolve({
|
|
ok: true,
|
|
json: async () => response,
|
|
blob: async () => ({ size: 1024 }),
|
|
});
|
|
});
|
|
};
|
|
|
|
export const mockFetchError = (error: string) => {
|
|
(global.fetch as any).mockRejectedValue(new Error(error));
|
|
};
|