Skip to content

Conversation

@Y-RyuZU
Copy link
Owner

@Y-RyuZU Y-RyuZU commented Jul 17, 2025

Summary

  • Implemented file count-based progress bars for scan operations across all translation tabs
  • Removed path settings functionality and implemented shared profile directory system
  • Enhanced translation history dialog with directory selection capability

Changes

Progress Bar Implementation (TX022)

  • Added real-time file count progress tracking during scan operations
  • Implemented visual progress bars showing current file being scanned
  • Added percentage display based on processed vs total file count
  • Unified progress UI across Mods, Quests, Guidebooks, and Custom Files tabs

Profile Directory Management (TX023)

  • Removed PathSettings component and PathsConfig interface completely
  • Implemented shared profile directory as session-only state in global store
  • All translation tabs now use the same profile directory
  • Enhanced translation history dialog with directory selection and fallback logic
  • Improved error handling for directory operations

Technical Improvements

  • Fixed TypeScript compilation errors
  • Resolved ESLint warnings
  • Optimized scan performance with better progress updates
  • Added proper NATIVE_DIALOG prefix handling
  • Improved UI responsiveness during scanning

Test Results

All PR validation checks passed:

  • ✅ TypeScript type checking
  • ✅ ESLint linting
  • ✅ Jest unit tests (108 tests)
  • ✅ Bun unit tests (52 tests)
  • ✅ E2E tests (17 tests)
  • ✅ Rust formatting and Clippy
  • ✅ Backend tests

Screenshots

The scan progress now shows:

  • Current file being scanned
  • Progress bar with percentage
  • File count (e.g., "45 / 120 files - 38%")

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added real-time scan progress tracking and visualization during file scanning operations across Mods, Quests, Guidebooks, and Custom Files tabs.
    • Introduced a setting to skip translation of items that already have existing translations.
    • Enabled viewing of detailed session logs directly from the translation history dialog.
    • Added cross-platform file path utilities for improved path handling.
    • Added commands to check for existing translations of mods, quests, and guidebooks.
    • Added a spinner component for improved loading indicators.
  • Enhancements

    • Improved error messages and UI feedback for directory and scanning errors.
    • Enhanced responsive design, animations, and interactive feedback for dialogs, buttons, checkboxes, inputs, tabs, and layout components.
    • Updated default OpenAI model identifier.
    • Improved JSON serialization consistency with sorted keys.
    • Refined internal state management for scanning and scan progress.
    • Disabled tab switching during scanning or translation operations with user notifications.
    • Improved translation skipping logic with detailed logging.
    • Enhanced path handling with cross-platform utilities.
    • Expanded maximum widths and heights for dialogs and layouts on very large screens.
  • Bug Fixes

    • Corrected method invocation in configuration service to align with static method usage.
  • Tests

    • Added end-to-end and unit tests for scanning, translation skipping, and JSON serialization utilities.
  • Chores

    • Updated localization files with new UI texts and error messages in English and Japanese.
    • Restructured CI workflow into multiple focused jobs with improved caching and security scanning.
    • Removed deprecated settings and components related to path configuration UI.

Y-RyuZU and others added 22 commits July 16, 2025 13:18
Implement CodeRabbit's suggestion to wrap the sorting logic in useMemo to prevent unnecessary recalculations on every render. This improves performance when dealing with large datasets by only recalculating when sessions or sortConfig change.

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

Co-Authored-By: Claude <[email protected]>
…ions

Add real-time progress feedback during file scanning operations showing
current file being processed and total count. Updates every 1 file or
1000ms (whichever comes first) following the "Simple over Easy" design.

- Add scan progress event emission in Rust backend with 1000ms throttling
- Add scan progress state management to Zustand store
- Update all tab components to display scan progress during operations
- Show "Scanning: filename (X files)" instead of generic "Scanning..."
Improve scan progress reporting to address user feedback about poor visibility:
- Show progress as "X / Y files (Z%)" instead of just "(X files)"
- Count total files before scanning for accurate progress percentage
- Update progress more frequently (every 10 files OR every 200ms)
- Emit progress events when finding relevant files (JAR, SNBT, JSON)
- Apply improvements to all scan types (mods, quests, guidebooks, custom files)

This provides better user feedback during scan operations with clear progress
indication and reduces the time when no progress is shown.
Fix the issue where scan progress was only shown during initial file
discovery but not during the time-consuming file analysis phase.

- Add progress updates during JAR analysis in mods-tab.tsx
- Add progress updates during quest file analysis in quests-tab.tsx
- Add progress updates during Patchouli book extraction in guidebooks-tab.tsx
- Add progress updates during custom file processing in custom-files-tab.tsx
- Add resetScanProgress() calls in all finally blocks

This ensures users see continuous progress updates throughout the entire
scan process, not just "Please wait..." during the analysis phase.
Add a compact progress bar to complement the text-based progress display
during scan operations. The progress bar shows visual completion percentage
alongside the existing "X / Y files (Z%)" text display.

Features:
- Small, compact progress bar (height: 1.5rem)
- Only shows when both processedCount and totalCount are available
- Centered with max-width for better visual balance
- Maintains the existing text progress display above it
- Consistent with the "Simple over Easy" design philosophy

This provides better visual feedback while keeping the interface clean and uncluttered.
Fix layout issues with the scan progress display:
- Set fixed width (w-80) for progress bar to prevent stretching/shrinking
- Change file name alignment from center to left (text-left)
- Keep progress statistics centered (text-center)
- Remove text-center from main container to allow individual control

This provides consistent visual layout regardless of file name length
and better readability with left-aligned file names.
Fix the scan progress container from expanding/contracting based on filename length:
- Set fixed width (w-96) for the progress content container
- Add truncate class to filename text to handle overflow
- Keep progress bar at fixed width (w-80) within the container

This ensures consistent layout regardless of filename length and prevents
the progress bar from appearing to stretch or shrink.
Fix the delay between clicking scan button and progress display appearing
by initializing scan progress state immediately when scanning begins.

Changes:
- Set initial scan progress state right after setScanning(true)
- Initialize with empty currentFile, 0 processedCount, undefined totalCount
- Set appropriate scanType for each tab (mods, quests, guidebooks, custom-files)
- Apply fix to all tab components consistently

This provides immediate visual feedback that scanning has started, instead of
waiting for the first file to be discovered/processed by the backend.
Improve scan button responsiveness especially during re-scans by:
- Move heavy state clearing operations to async setTimeout to avoid blocking UI
- Show "Initializing scan..." message immediately for better user feedback
- Reduce UI blocking during translation targets clearing
- Apply optimizations to all tab components consistently

This reduces the perceived delay when clicking scan button after previous scans
by preventing React re-render blocking during large state updates.
Revert problematic async setTimeout and implement more effective optimizations:
- Remove setTimeout that caused additional delay
- Add conditional state updates to avoid unnecessary operations
- Use useCallback to memoize handleScan function
- Import useMemo and useCallback for future optimizations
- Only clear state if it actually has content

This provides immediate response while avoiding unnecessary React re-renders
and state updates during re-scan operations.
Revert useCallback and conditional state updates that were causing delays:
- Remove useCallback with problematic dependencies (onScan changes every render)
- Remove conditional state clearing that adds unnecessary checks
- Return to simple, direct state updates for better performance
- Keep only essential optimization: check translationResults length before clearing

The original implementation was actually faster. The perceived delay was not
from React re-renders but from the actual scan processing time.
…hilosophy

Remove unnecessary optimizations and return to straightforward implementation:
- Remove useCallback and complex dependency management
- Remove conditional state clearing (if checks)
- Remove unused imports (useCallback, useMemo)
- Use direct state updates for clarity and simplicity
- Keep only essential functionality

This follows the "EasyよりもSimple" design principle - prefer simple,
understandable code over complex optimizations that don't provide clear benefits.
Fix the delay between scan start and progress display by adding intermediate
progress updates immediately after file discovery phase:

- Show "Analyzing [file type]..." after file discovery completes
- Display total file count before detailed analysis begins
- Apply to all tab types (mods, quests, guidebooks, custom files)
- Provide immediate visual feedback to users

This addresses the two-phase scan process:
1. File discovery (fast) - now shows immediate progress
2. File analysis (slow) - already had progress updates

Users now see continuous progress feedback throughout the entire scan process.
Fix the issue where scan button remains in pressed state due to UI blocking:
- Move heavy state clearing operations to requestAnimationFrame
- Allow UI to update with isScanning=true before clearing large datasets
- Extract directory path before clearing to avoid delays
- Prevent synchronous React re-renders from blocking button animations

This ensures the scan button animation and progress display appear immediately
without being blocked by clearing existing translation targets.
- Add click feedback and hover states to all interactive elements
- Implement smooth transitions for buttons, inputs, and form controls
- Add loading animations with spinners for scan and translate operations
- Enhance dialog and modal animations with backdrop blur
- Add staggered animations for table rows and data loading
- Create consistent animation timing (200-300ms) across components
- Improve loading states with enhanced visual feedback
- Add error display animations for better user awareness
…essages

- Add check functions for existing translations in mods, quests, and guidebooks
- Implement skipExistingTranslations functionality to avoid duplicate work
- Improve error messages with i18n translation keys for better localization
- Add validation for mod, quest, and guidebook translation files
- Enhance filesystem error handling with structured error messages
- Add PathsConfig interface with directory path properties
- Include paths property in AppConfig interface
- Add PATH_DEFAULTS constants for default path values
- Fix TypeScript compilation errors related to missing paths property
Backend Changes:
- Add scan progress event emission in filesystem.rs with file count tracking
- Add translation existence check functions for mods, quests, and guidebooks
- Add read_session_log function for session log retrieval
- Add test features and dev dependencies to Cargo.toml
- Export new command functions in lib.rs

Frontend Changes:
- Implement scan progress UI with progress bars and file count display
- Add scan state management and progress tracking
- Update tab switching to prevent switching during scan operations
- Add loading animations and improved UI feedback
- Update various UI components with progress-related improvements

Features:
- Real-time progress updates during file scanning
- File count-based progress indicators
- Responsive UI with loading states
- Tab locking during scan operations
- Enhanced error handling and user feedback
- Replace serde_json::to_string_pretty with serialize_json_sorted in backup.rs
- Update config.rs to use sorted JSON serialization for all config operations
- Add session ID format validation in backup.rs
- Update lang_file_test.rs to test sorted JSON functionality
- Ensure consistent JSON key ordering across all output files
- Improve file diff readability and maintainability
…rovements

- Add session ID validation with proper format checking
- Implement session log reading functionality for debugging
- Add JSON sorting for consistent backup metadata and config output
- Improve backup session management with better validation
- Enhance logging system with session-specific log retrieval
English translations:
- Add skipExistingTranslations setting translations
- Add scanInProgress error message
- Add detailed error messages for directory not found scenarios
- Add session log related translations

Japanese translations:
- Add corresponding Japanese translations for all new English strings
- Maintain consistency with existing Japanese translation style
- Add proper Japanese translations for scan progress features

Features:
- Support for skip existing translations setting
- Enhanced error message localization
- Session log viewing translations
- Improved user experience with localized messages
- Remove unused FileService import that was causing ESLint error
- Fix linting issue after applying cargo fmt to Rust files
- Ensure all PR validation checks pass
@coderabbitai
Copy link

coderabbitai bot commented Jul 17, 2025

Walkthrough

This update introduces scan progress tracking and skipping of already translated files across mods, quests, and guidebooks, with corresponding UI and backend enhancements. It adds new backend commands for translation existence checks, implements cross-platform path utilities, and refines error reporting and UI responsiveness. Numerous UI components receive responsive and interactive style improvements, and session log viewing is integrated into the translation history dialog. JSON serialization is standardized for sorted key output, and configuration defaults and structure are updated to support new features.

Changes

File(s) Change Summary
public/locales/en/common.json, public/locales/ja/common.json Added new UI, error, scan progress, and session log messages; updated existing error strings; added translation skipping setting entries.
src-tauri/Cargo.toml Enabled "test" feature for tauri; added dev dependencies.
src-tauri/src/backup.rs Added strict session ID validation; switched JSON serialization to sorted key output.
src-tauri/src/config.rs Replaced JSON serialization with sorted key output for config files.
src-tauri/src/filesystem.rs Added scan progress event emission and struct; implemented sorted JSON serialization utility; updated file writing to use sorted JSON.
src-tauri/src/lib.rs Exposed new backend commands for translation existence checks and session log reading.
src-tauri/src/logging.rs Added command to read session log files for a given session.
src-tauri/src/minecraft/mod.rs Added commands to check for existing mod/quest/guidebook translations; switched Patchouli book writing to sorted JSON serialization.
src-tauri/src/tests/lang_file_test.rs Replaced file I/O tests with in-memory JSON sorting/serialization tests.
src/__tests__/e2e/skip-existing-translations-e2e.test.ts Added E2E tests for skip existing translations configuration.
src/app/page.tsx Enhanced loading UI with spinner; blocked tab switching during scan or translation; disabled tab triggers during operations.
src/components/layout/header.tsx, src/components/layout/main-layout.tsx Improved responsive layout and spacing for large screens.
src/components/settings/settings-dialog.tsx Removed directory selection logic; expanded dialog size for large screens.
src/components/settings/translation-settings.tsx Added skip existing translations toggle with UI and config binding.
src/components/tabs/common/translation-tab.tsx Added scan progress prop, progress display, error handling, and UI/animation enhancements.
src/components/tabs/custom-files-tab.tsx, src/components/tabs/guidebooks-tab.tsx, src/components/tabs/mods-tab.tsx, src/components/tabs/quests-tab.tsx Integrated scan progress tracking, event listeners, improved path handling, and skipping of already translated files.
src/components/ui/button.tsx, src/components/ui/card.tsx, src/components/ui/checkbox.tsx, src/components/ui/completion-dialog.tsx, src/components/ui/dialog.tsx, src/components/ui/input.tsx, src/components/ui/log-dialog.tsx, src/components/ui/progress.tsx, src/components/ui/scroll-area.tsx, src/components/ui/select.tsx, src/components/ui/spinner.tsx, src/components/ui/switch.tsx, src/components/ui/tabs.tsx Enhanced responsive design, interactive transitions, and animation effects across UI components; added new Spinner component.
src/components/ui/translation-history-dialog.tsx Added session log viewing dialog with backend integration, loading/error handling, and expanded UI.
src/lib/constants/defaults.ts, src/lib/types/config.ts Updated default OpenAI model; introduced skipExistingTranslations config option and types; removed paths config.
src/lib/services/config-service.ts Fixed static method invocation for API key migration; removed paths from config conversion.
src/lib/store/index.ts Added scanning state and scan progress tracking to app store, plus profileDirectory state.
src/lib/utils/path-utils.ts New cross-platform path utility functions for filename, directory, joining, normalization, and relative path computation.
.github/workflows/pr-validation.yml Restructured CI workflow into multiple jobs with improved caching, test coverage, and security scanning.
src/__tests__/e2e/fixtures/output/realistic/complexmod.ja_jp.json, src/__tests__/e2e/fixtures/output/simple/getting_started.ja_jp.snbt, src/__tests__/e2e/fixtures/output/simple/samplemod.ja_jp.json Added new Japanese localization files for mods and quests for testing.
src/components/settings/path-settings.tsx, src/components/tabs/settings-tab.tsx Removed path settings and settings tab components related to directory path management.
src/lib/services/translation-runner.ts Changed source of Minecraft directory path to use profileDirectory from app store.

Sequence Diagram(s)

sequenceDiagram
    participant UI
    participant Store
    participant Backend
    participant Filesystem

    UI->>Store: Set isScanning = true
    UI->>Backend: Start scan (e.g., get_mod_files)
    Backend->>Filesystem: Scan directory, count files
    loop For each file (periodically)
        Filesystem->>Backend: Emit scan_progress event (current file, counts)
        Backend->>UI: scan_progress event
        UI->>Store: Update scanProgress state
    end
    Filesystem->>Backend: Complete scan, emit final scan_progress
    Backend->>UI: scan_progress (completed)
    UI->>Store: Reset scanProgress, set isScanning = false
Loading
sequenceDiagram
    participant UI
    participant Backend

    UI->>Backend: check_mod_translation_exists (mod_path, mod_id, lang)
    Backend->>Filesystem: Open mod archive, check for lang files
    Filesystem-->>Backend: Exists? (true/false)
    Backend-->>UI: Return true/false

    UI->>Backend: check_quest_translation_exists (quest_path, lang)
    Backend->>Filesystem: Check for quest translation files
    Filesystem-->>Backend: Exists? (true/false)
    Backend-->>UI: Return true/false

    UI->>Backend: check_guidebook_translation_exists (guidebook_path, mod_id, book_id, lang)
    Backend->>Filesystem: Open guidebook archive, check for translation file
    Filesystem-->>Backend: Exists? (true/false)
    Backend-->>UI: Return true/false
Loading
sequenceDiagram
    participant UI
    participant Backend

    UI->>Backend: read_session_log (minecraft_dir, session_id)
    Backend->>Filesystem: Read log file for session
    alt File exists
        Filesystem-->>Backend: Return log content
        Backend-->>UI: Return log content
    else File missing/error
        Filesystem-->>Backend: Return error
        Backend-->>UI: Return error
    end
Loading

Possibly related PRs

  • TX016 Translation Backup System Implementation #20: Implements a translation backup system with session-based backup commands and a translation history dialog using a sortable table, overlapping with this PR's enhancements to translation session management, backup commands, and session log UI.

Poem

🐇✨
A scan begins, the files abound,
With spinners whirling round and round.
The rabbit skips what’s done before,
And shows you progress, logs, and more!
Paths are tamed, the UI shines—
Sorted JSON, responsive lines.
Hop along, translation friend—
This update’s magic never ends!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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

🔭 Outside diff range comments (2)
src-tauri/src/filesystem.rs (2)

189-255: Add progress tracking for KubeJS lang file scanning.

The KubeJS lang file scanning section doesn't emit progress events, which creates an inconsistent user experience compared to SNBT file scanning.

Add progress tracking similar to the SNBT scanning section. You'll need to count files first and emit progress events during the scan.


381-381: Use consistent error message format.

This error message doesn't follow the new prefixed format used elsewhere in the file.

-            return Err("No FTB quests directory found. Checked: config/ftbquests/quests/, config/ftbquests/normal/, and config/ftbquests/".to_string());
+            return Err("errors.questsDirectoryNotFound:::config/ftbquests/quests/, config/ftbquests/normal/, config/ftbquests/".to_string());
♻️ Duplicate comments (2)
src/components/tabs/guidebooks-tab.tsx (1)

220-220: Consistency: Default value for skipExistingTranslations.

Same as in mods-tab.tsx, this defaults to true. For consistency across all tabs, consider using the same default value approach.

src/components/tabs/quests-tab.tsx (1)

272-272: Consistency: Default value for skipExistingTranslations.

Same default true value as other tabs. Consider standardizing this across all components.

🧹 Nitpick comments (10)
src/lib/utils/path-utils.ts (1)

42-72: Consider edge case handling in relative path calculation.

The function handles most cases well, but the fallback logic (lines 64-71) that returns the last 2 segments when paths don't match might be confusing. Consider documenting this behavior more clearly or providing a more predictable fallback.

  // If not a child of base path, return last 2 segments as fallback
+ // This provides a meaningful relative representation even when paths don't share a common base
  const parts = fullPath.split(/[/\\]/);
  if (parts.length >= 2) {
    return parts.slice(-2).join('/');
  }
src/components/tabs/mods-tab.tsx (2)

49-91: Consider adding error handling for the event listener cleanup.

The current implementation catches errors during listener setup but returns an empty function. Consider logging the error or providing user feedback when the scan progress listener fails to initialize.

 } catch (error) {
   console.error('Failed to set up scan progress listener:', error);
-  return () => {};
+  // Return a no-op function but ensure we don't lose the error context
+  return () => {
+    console.warn('Scan progress listener was not properly initialized');
+  };
 }

233-233: Consider the default value for skipExistingTranslations.

The nullish coalescing operator defaults to true, which means translations will be skipped by default even if the user hasn't configured this setting. This might be unexpected behavior for users.

Consider defaulting to false to ensure all items are translated unless explicitly configured otherwise:

-if (config.translation.skipExistingTranslations ?? true) {
+if (config.translation.skipExistingTranslations ?? false) {
src/components/tabs/custom-files-tab.tsx (1)

50-93: Consider improving error handling for the listener setup.

The scan progress listener is well-implemented. However, the error handling could be improved by notifying the user when the listener fails to set up.

Consider propagating the error to the UI:

 } catch (error) {
   console.error('Failed to set up scan progress listener:', error);
+  setError('Failed to set up scan progress listener');
   return () => {};
 }
src-tauri/src/minecraft/mod.rs (3)

844-881: Remove unnecessary async from synchronous function.

The implementation correctly checks for both JSON and legacy .lang translation files. However, the function doesn't perform any async operations.

-pub async fn check_mod_translation_exists(
+pub fn check_mod_translation_exists(
     mod_path: &str,
     mod_id: &str,
     target_language: &str,
 ) -> Result<bool, String> {

884-909: Remove unnecessary async and improve error messages.

The implementation correctly checks for quest translation files, but has the same async issue.

-pub async fn check_quest_translation_exists(
+pub fn check_quest_translation_exists(
     quest_path: &str,
     target_language: &str,
 ) -> Result<bool, String> {
     let path = PathBuf::from(quest_path);
-    let parent = path.parent().ok_or("Failed to get parent directory")?;
+    let parent = path.parent().ok_or_else(|| format!("Failed to get parent directory for: {}", quest_path))?;
     let file_stem = path
         .file_stem()
-        .ok_or("Failed to get file stem")?
+        .ok_or_else(|| format!("Failed to get file stem for: {}", quest_path))?
         .to_string_lossy();

912-944: Remove unnecessary async from synchronous function.

The guidebook translation check is correctly implemented following Patchouli's file structure.

-pub async fn check_guidebook_translation_exists(
+pub fn check_guidebook_translation_exists(
     guidebook_path: &str,
     mod_id: &str,
     book_id: &str,
     target_language: &str,
 ) -> Result<bool, String> {
src/components/tabs/common/translation-tab.tsx (2)

217-228: Consider using a more unique separator for structured errors.

The error handling improvements are good, but the ::: separator might appear in actual error messages or paths.

Consider using a more unique separator or a structured error format:

- if (errorMessage.startsWith('errors.') && errorMessage.includes(':::')) {
-   const [translationKey, path] = errorMessage.split(':::');
+ if (errorMessage.startsWith('errors.') && errorMessage.includes('|PATH|')) {
+   const [translationKey, path] = errorMessage.split('|PATH|');

514-515: Consider performance impact of staggered animations with large datasets.

The horizontal scrolling and animations are nice UX improvements. However, the staggered animation might cause performance issues with hundreds of items.

Consider limiting animations to the first N visible items:

- style={{ animationDelay: `${index * 50}ms` }}>
+ style={{ animationDelay: `${Math.min(index, 10) * 50}ms` }}>

Also applies to: 640-640, 659-659

src-tauri/src/filesystem.rs (1)

89-158: Consider adding error handling for progress event emission.

The progress tracking implementation looks good. However, if an error occurs during directory traversal, the completion event might not be emitted, leaving the UI in a "scanning" state.

Consider wrapping the directory traversal in a result handler to ensure the completion event is always emitted:

+    let scan_result = (|| -> std::result::Result<Vec<String>, String> {
     // Walk through the directory and find all JAR files
     let mut processed_count = 0;
     let mut last_emit = Instant::now();
     const EMIT_INTERVAL: Duration = Duration::from_millis(200);

     for entry in WalkDir::new(target_dir)
         .max_depth(1)
         .into_iter()
         .filter_map(|e| e.ok())
     {
         // ... existing code ...
     }
+        Ok(mod_files)
+    })();

     // Emit completion event
     let _ = app_handle.emit(
         "scan_progress",
         ScanProgressPayload {
             current_file: "".to_string(),
             processed_count,
             total_count: Some(total_files),
             scan_type: "mods".to_string(),
             completed: true,
         },
     );

-    debug!("Found {} mod files", mod_files.len());
-    Ok(mod_files)
+    match scan_result {
+        Ok(files) => {
+            debug!("Found {} mod files", files.len());
+            Ok(files)
+        }
+        Err(e) => Err(e)
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 601ba91 and 9046861.

⛔ Files ignored due to path filters (1)
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (40)
  • public/locales/en/common.json (3 hunks)
  • public/locales/ja/common.json (3 hunks)
  • src-tauri/Cargo.toml (2 hunks)
  • src-tauri/src/backup.rs (5 hunks)
  • src-tauri/src/config.rs (4 hunks)
  • src-tauri/src/filesystem.rs (15 hunks)
  • src-tauri/src/lib.rs (3 hunks)
  • src-tauri/src/logging.rs (1 hunks)
  • src-tauri/src/minecraft/mod.rs (3 hunks)
  • src-tauri/src/tests/lang_file_test.rs (1 hunks)
  • src/__tests__/e2e/skip-existing-translations-e2e.test.ts (1 hunks)
  • src/app/page.tsx (3 hunks)
  • src/components/layout/header.tsx (1 hunks)
  • src/components/layout/main-layout.tsx (1 hunks)
  • src/components/settings/settings-dialog.tsx (1 hunks)
  • src/components/settings/translation-settings.tsx (2 hunks)
  • src/components/tabs/common/translation-tab.tsx (11 hunks)
  • src/components/tabs/custom-files-tab.tsx (6 hunks)
  • src/components/tabs/guidebooks-tab.tsx (6 hunks)
  • src/components/tabs/mods-tab.tsx (6 hunks)
  • src/components/tabs/quests-tab.tsx (8 hunks)
  • src/components/ui/button.tsx (1 hunks)
  • src/components/ui/card.tsx (1 hunks)
  • src/components/ui/checkbox.tsx (1 hunks)
  • src/components/ui/completion-dialog.tsx (5 hunks)
  • src/components/ui/dialog.tsx (2 hunks)
  • src/components/ui/input.tsx (1 hunks)
  • src/components/ui/log-dialog.tsx (2 hunks)
  • src/components/ui/progress.tsx (1 hunks)
  • src/components/ui/scroll-area.tsx (2 hunks)
  • src/components/ui/select.tsx (2 hunks)
  • src/components/ui/spinner.tsx (1 hunks)
  • src/components/ui/switch.tsx (1 hunks)
  • src/components/ui/tabs.tsx (2 hunks)
  • src/components/ui/translation-history-dialog.tsx (12 hunks)
  • src/lib/constants/defaults.ts (2 hunks)
  • src/lib/services/config-service.ts (1 hunks)
  • src/lib/store/index.ts (2 hunks)
  • src/lib/types/config.ts (5 hunks)
  • src/lib/utils/path-utils.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (9)
src-tauri/src/config.rs (1)
src-tauri/src/filesystem.rs (1)
  • serialize_json_sorted (820-824)
src/components/ui/tabs.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src/components/ui/switch.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src-tauri/src/backup.rs (1)
src-tauri/src/filesystem.rs (1)
  • serialize_json_sorted (820-824)
src/components/ui/spinner.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src-tauri/src/lib.rs (2)
src-tauri/src/logging.rs (1)
  • read_session_log (557-578)
src-tauri/src/minecraft/mod.rs (3)
  • check_guidebook_translation_exists (913-944)
  • check_mod_translation_exists (846-881)
  • check_quest_translation_exists (885-909)
src/components/ui/scroll-area.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src/components/tabs/mods-tab.tsx (4)
src/lib/store/index.ts (1)
  • useAppStore (116-436)
src/lib/services/file-service.ts (2)
  • FileService (188-382)
  • invoke (202-209)
src/lib/types/minecraft.ts (2)
  • TranslationTarget (103-120)
  • ModInfo (13-28)
src/lib/utils/path-utils.ts (1)
  • getRelativePath (42-72)
src/lib/types/config.ts (1)
src/lib/constants/defaults.ts (4)
  • TRANSLATION_DEFAULTS (36-48)
  • UI_DEFAULTS (117-131)
  • UPDATE_DEFAULTS (136-141)
  • PATH_DEFAULTS (106-112)
🪛 Biome (1.9.4)
src/lib/services/config-service.ts

[error] 154-154: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 154-154: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

⏰ 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: Build - x86_64-pc-windows-msvc
  • GitHub Check: Build - aarch64-apple-darwin
  • GitHub Check: Build - x86_64-apple-darwin
  • GitHub Check: Build - x86_64-unknown-linux-gnu
  • GitHub Check: Validate PR
  • GitHub Check: Security Scan
🔇 Additional comments (93)
src-tauri/Cargo.toml (2)

24-24: LGTM: Test feature enabled for Tauri dependency.

Adding the "test" feature to the Tauri dependency enables testing capabilities for the backend, which aligns with the PR's testing improvements.


38-40: LGTM: Dev dependencies added for testing support.

The tempfile and tokio dev dependencies provide necessary testing infrastructure for file operations and async testing, which supports the refactored test code mentioned in the AI summary.

src/components/layout/header.tsx (2)

79-79: LGTM: Enhanced responsive design for large screens.

The addition of 2xl breakpoint classes improves the header layout for very large displays with appropriate max-width, padding, and height adjustments.


80-81: LGTM: Consistent responsive spacing and typography.

The gap and font size adjustments maintain visual hierarchy and improve readability on larger screens, consistent with the broader UI responsiveness improvements.

src/components/ui/button.tsx (3)

8-8: LGTM: Enhanced button base styling with responsive design.

The comprehensive styling improvements include responsive typography, smooth transitions, active state animations, and better accessibility features. The implementation is well-structured and follows modern design patterns.


13-22: LGTM: Improved visual feedback with shadow effects.

The hover and active shadow effects provide excellent visual feedback across all button variants, enhancing the user experience while maintaining consistency.


25-28: LGTM: Consistent responsive sizing across variants.

The 2xl breakpoint sizing adjustments ensure buttons scale appropriately on larger screens while maintaining proper proportions and spacing.

src/components/ui/scroll-area.tsx (4)

8-10: LGTM: Well-defined props interface with orientation control.

The ScrollAreaProps interface properly extends the base component props and adds the orientation option with appropriate type constraints.


15-17: LGTM: Backward-compatible default orientation.

The default "vertical" orientation maintains backward compatibility while supporting the new functionality.


21-21: LGTM: Proper overflow handling for scroll areas.

Adding overflow-hidden to the root container is appropriate for scroll area functionality and prevents content from overflowing unexpectedly.


30-35: LGTM: Conditional scrollbar rendering implementation.

The conditional rendering logic correctly shows scrollbars based on the orientation prop, supporting all three modes (vertical, horizontal, both) as intended.

src/lib/utils/path-utils.ts (6)

11-17: LGTM: Robust cross-platform filename extraction.

The function correctly handles both Windows and Unix path separators and provides appropriate fallback behavior for edge cases.


24-34: LGTM: Directory path extraction with normalization.

The implementation properly extracts directory paths and normalizes them to forward slashes for cross-platform consistency.


79-87: LGTM: Effective path joining with cleanup.

The function correctly filters empty segments and normalizes multiple slashes, providing clean path joining functionality.


94-96: LGTM: Simple and effective path normalization.

The normalization function is straightforward and serves its purpose for cross-platform compatibility.


104-118: LGTM: Comprehensive absolute path detection.

The function correctly identifies Windows drive letters, UNC paths, and Unix absolute paths, covering all major platforms.


125-135: LGTM: Parent directory extraction with proper normalization.

The function correctly handles parent directory calculation while maintaining cross-platform compatibility through normalization.

src/components/ui/card.tsx (1)

13-13: Good UX enhancement with smooth hover transitions.

The addition of transition effects and hover shadow enhancement improves the interactive feel of card components. The 200ms duration provides a good balance between responsiveness and smoothness.

src/components/layout/main-layout.tsx (1)

54-54: Excellent responsive design enhancement for larger screens.

The progressive padding and max-width adjustments for xl and 2xl breakpoints will provide better utilization of space on larger displays while maintaining good readability and layout proportions.

src/components/ui/progress.tsx (1)

24-24: Perfect animation timing for progress indicators.

The 300ms duration with ease-out timing provides smooth and natural progress bar animations, which is especially important for the new file count-based progress bars being implemented in this PR.

src/lib/services/config-service.ts (1)

154-154: Correct fix for static method invocation.

Good catch! Using the class name instead of this for static method calls is the proper approach and eliminates the confusing this reference in a static context.

src/components/ui/select.tsx (2)

40-40: Enhanced select trigger interactions with smooth transitions.

The addition of transition effects for color, box-shadow, and border-color properties, along with the hover and open state styling, significantly improves the visual feedback and user experience of the select component.


110-110: Smooth color transitions for select items.

The color transition with 150ms duration and ease-in-out timing provides polished visual feedback when users interact with select items, contributing to a cohesive and responsive UI experience.

src/components/ui/completion-dialog.tsx (1)

91-91: LGTM: Consistent responsive styling improvements

The responsive styling updates for the 2xl breakpoint are well-implemented and consistent throughout the component. The changes appropriately scale dialog dimensions, text sizes, spacing, and interactive elements for very large screens, enhancing the user experience across different display sizes.

Also applies to: 121-121, 132-132, 142-142, 145-145, 166-166

src-tauri/src/config.rs (1)

1-1: LGTM: Consistent JSON serialization with sorted keys

The replacement of serde_json::to_string_pretty with serialize_json_sorted is a good improvement that ensures consistent JSON output formatting across the application. The changes maintain the same error handling patterns while providing sorted key output, which improves readability and consistency of configuration files.

Also applies to: 166-166, 206-206, 238-238

src/components/settings/settings-dialog.tsx (1)

88-88: LGTM: Responsive styling improvement and path settings removal

The dialog dimension updates for the 2xl breakpoint are consistent with the responsive design improvements throughout the application. The removal of PathSettings functionality (as mentioned in the AI summary) aligns with the PR objective of centralizing path management through a shared profile directory system.

src/components/ui/tabs.tsx (1)

45-45: LGTM: Enhanced tab interactions with smooth animations

The styling improvements add excellent interactive feedback to the tabs component:

  • The TabsTrigger now includes comprehensive transitions, hover effects, and active state scaling that provide better user experience
  • The TabsContent animation with fade-in and slide-in effects creates smooth transitions between tabs

These enhancements align well with the overall UI improvements in the PR and follow good UX practices.

Also applies to: 60-60

src/lib/constants/defaults.ts (2)

10-10: LGTM: Corrected OpenAI model identifier

The change from "o4-mini-2025-04-16" to "gpt-4o-mini" corrects the model identifier to use the proper OpenAI naming convention. This ensures compatibility with the OpenAI API.


103-112: LGTM: Added path defaults for consistent configuration

The new PATH_DEFAULTS constant provides a centralized location for default directory path values, which aligns with the PR's objective of improving path management. This supports the move to a shared profile directory system and ensures consistent initialization of path configurations.

src/components/ui/input.tsx (1)

11-11: LGTM! Consistent responsive design improvements.

The 2xl breakpoint enhancements follow a consistent pattern with proper scaling of dimensions, padding, and text sizes. The addition of border-color to the transition properties will provide smoother visual feedback during focus states.

src/app/page.tsx (4)

21-21: LGTM! Proper integration of scanning state.

The addition of isScanning from the app store is correctly implemented alongside the existing isTranslating state.


46-54: LGTM! Enhanced loading UI with proper spinner.

The loading state now provides better visual feedback with a proper spinner animation and improved styling. The fallback text handling for unmounted/unready states is appropriate.


67-72: LGTM! Consistent scanning state handling.

The scanning state check follows the same pattern as the translation state check, providing consistent user experience and preventing tab switching during operations.


80-90: LGTM! Proper tab trigger disabling logic.

The tab triggers are correctly disabled during both translation and scanning operations, but only for non-active tabs, allowing users to stay on the current tab.

src/components/ui/log-dialog.tsx (2)

330-330: LGTM! Consistent responsive dialog sizing.

The 2xl breakpoint enhancements expand the dialog appropriately for very large screens, improving usability and readability.


345-345: LGTM! Improved readability on large screens.

The increased padding and text size at the 2xl breakpoint will improve log readability on very large displays.

src/components/ui/spinner.tsx (1)

1-25: Verify Tailwind border-3 utility availability

The new spinner at src/components/ui/spinner.tsx uses border-3, which isn’t included in Tailwind’s default borderWidth scale. Please ensure your tailwind.config.* defines a 3px (or rem) border width, or adjust to a supported value (e.g. border-2/border-4).

• File needing attention:
src/components/ui/spinner.tsx (sizeClasses.lg uses border-3)

src/components/ui/checkbox.tsx (2)

17-17: Enhanced interactive states improve user experience.

The transition from transition-shadow to transition-all duration-200 ease-in-out with added hover and active states creates smoother, more responsive user interactions. The comprehensive className properly handles various states including focus, disabled, and validation states.


24-24: Smooth animation transitions for state changes.

The addition of transition-all duration-200 ease-in-out with zoom-in/zoom-out animations provides excellent visual feedback for checked/unchecked state transitions. The animation timing is consistent with the root element.

src/components/ui/switch.tsx (2)

16-16: Consistent interactive behavior across UI components.

The enhanced className with transition timing, hover states, and active scaling creates a polished user experience. The conditional hover states (hover:data-[state=checked]:bg-primary/90 and hover:data-[state=unchecked]:bg-input/70) provide appropriate visual feedback for different switch states.


24-24: Smooth thumb transitions complement the enhanced switch behavior.

The addition of duration-200 ease-in-out to the thumb's transform transition ensures consistent animation timing with the root switch element, creating a cohesive user experience.

src-tauri/src/lib.rs (3)

26-26: New session log reading capability added.

The import of read_session_log enables the frontend to access session-specific log files, supporting the new log viewing feature mentioned in the PR objectives.


29-31: Translation existence checking commands support skip functionality.

The addition of check_mod_translation_exists, check_quest_translation_exists, and check_guidebook_translation_exists commands enables the frontend to implement the "skip existing translations" feature mentioned in the PR objectives. These commands allow checking for existing language files before processing.


83-85: Properly exposed new commands in Tauri invoke handler.

All new commands are correctly added to the tauri::generate_handler! macro, making them accessible from the frontend. The commands are logically grouped and follow the existing pattern.

Also applies to: 121-121

src-tauri/src/logging.rs (1)

555-578: Well-implemented session log reading with proper error handling.

The read_session_log function correctly constructs the log file path using the established directory structure and provides appropriate error handling for both missing files and read failures. The error messages are descriptive and will help with debugging.

The path construction ({minecraft_dir}/logs/localizer/{session_id}/localizer.log) aligns with the directory structure used by other functions in this file, ensuring consistency.

src/components/settings/translation-settings.tsx (2)

62-62: Minor UI enhancement for visual consistency.

The addition of transition-colors duration-200 hover:bg-muted/70 to the token-based chunking container provides subtle visual feedback, consistent with the broader UI improvements across the codebase.


136-156: Well-implemented skip existing translations setting.

The new setting follows the established pattern used by other settings in the component:

  • Clear label and descriptive hint text using i18n
  • Proper Switch component with controlled state
  • Correct state management using the config object with spreading
  • Default value of true aligns with the PR objective of skipping already translated files

The implementation maintains consistency with the existing codebase and provides the expected functionality.

src-tauri/src/backup.rs (3)

1-1: LGTM: Clean import for JSON serialization consistency.

The import of serialize_json_sorted aligns with the project-wide standardization of JSON serialization with sorted keys.


143-146: LGTM: Consistent JSON serialization with sorted keys.

The replacement of serde_json::to_string_pretty with serialize_json_sorted is appropriate and maintains proper error handling while ensuring consistent key ordering in backup metadata.


426-428: LGTM: Consistent JSON serialization for translation summaries.

The update maintains proper error handling while ensuring consistent key ordering in translation summary files, completing the JSON serialization standardization in this module.

src/components/ui/dialog.tsx (3)

41-41: LGTM: Enhanced dialog overlay with improved visual effects.

The addition of backdrop-blur-sm and consistent animation durations (data-[state=open]:duration-300 and data-[state=closed]:duration-200) provides better visual feedback and follows modern UI patterns where close animations are slightly faster than open animations.


60-60: LGTM: Consistent dialog content animations.

The subtle slide animations (slide-in-from-top-[2%] and slide-out-to-top-[2%]) with matching duration values provide smooth dialog transitions that enhance user experience without being distracting.


66-66: LGTM: Enhanced close button interactivity.

The transition to transition-all duration-200 with scale effects (hover:scale-110 active:scale-95) provides excellent tactile feedback that matches the dialog's animation timing and improves user interaction without being overwhelming.

src/lib/store/index.ts (3)

98-110: LGTM: Well-structured scanning state interface.

The scanning state additions are well-designed:

  • isScanning flag for simple boolean tracking
  • scanProgress object with appropriate fields for detailed progress information
  • Optional fields (totalCount, scanType) provide flexibility
  • setScanProgress with partial update capability for efficiency
  • Consistent naming and structure with existing store patterns

394-414: LGTM: Correct implementation of scanning state management.

The implementation follows established Zustand patterns:

  • Simple boolean setter for isScanning
  • Proper initial state with appropriate defaults
  • setScanProgress correctly merges partial updates using spread operator
  • resetScanProgress properly resets all fields to initial values
  • Consistent with existing store patterns and naming conventions

97-97: LGTM: Clean integration with existing state.

The scanning state additions are well-integrated without disrupting existing functionality. The separation of concerns between scanning and translation state is appropriate and maintains the store's logical organization.

src-tauri/src/tests/lang_file_test.rs (4)

6-6: LGTM: Appropriate test imports.

The import of serialize_json_sorted and sort_json_object is correct and necessary for testing the JSON sorting utilities.


8-37: LGTM: Comprehensive test for basic JSON object sorting.

The test is well-structured with clear test data and appropriate assertions. It effectively validates that sort_json_object correctly sorts keys alphabetically in a flat JSON object.


39-79: LGTM: Thorough test for nested JSON object sorting.

The test effectively validates recursive key sorting in nested JSON objects. The two-level nesting scenario with appropriate assertions ensures that the sort_json_object function works correctly for complex data structures.


81-105: LGTM: Excellent end-to-end test for JSON serialization.

The test comprehensively validates serialize_json_sorted by checking both the parsed JSON structure and the string representation. The string position checks are particularly clever for verifying serialization order, ensuring the function works correctly in real-world scenarios.

src/lib/types/config.ts (4)

26-40: LGTM: Well-designed PathsConfig interface.

The interface is comprehensive and well-documented, providing clear typing for all necessary directory paths. The property names are descriptive and the JSDoc comments enhance maintainability.


116-117: LGTM: Clear addition for translation skipping feature.

The skipExistingTranslations property is well-named, appropriately optional for backward compatibility, and clearly documented. It aligns perfectly with the PR objectives.


54-55: LGTM: Proper integration of PathsConfig interface.

The update to use the PathsConfig interface improves type safety and provides better structure for path-related configuration.


169-184: LGTM: Proper implementation of new configuration defaults.

The default configuration correctly implements the new interfaces:

  • skipExistingTranslations: true is a sensible default for avoiding duplicate work
  • The paths configuration properly uses PATH_DEFAULTS values
  • The structure maintains consistency with the interface definitions
public/locales/en/common.json (1)

60-63: LGTM! Localization entries are well-structured.

The new localization entries for skip existing translations, scan progress, and error messages follow consistent naming conventions and use proper placeholder syntax.

Also applies to: 180-191, 257-260

src/components/tabs/quests-tab.tsx (1)

379-398: Well-implemented language suffix handling.

The logic correctly handles:

  • Special case for DefaultQuests.lang files
  • Removal of existing language suffixes to prevent duplication
  • Proper file extension preservation

Good defensive programming with the regex pattern.

public/locales/ja/common.json (1)

60-63: Japanese translations are consistent and well-formatted.

The Japanese translations properly mirror the English locale structure and use appropriate terminology.

Also applies to: 180-191, 257-260

src/components/ui/translation-history-dialog.tsx (9)

3-3: LGTM!

The new imports are correctly added and used in the component.

Also applies to: 8-8


89-89: LGTM!

The onViewLogs prop is properly added and the View Logs button is well-implemented with proper icon and localization.

Also applies to: 132-143


174-174: LGTM!

The onViewLogs prop is correctly propagated through the component hierarchy.

Also applies to: 179-179, 270-270


283-287: LGTM!

The state variables for managing the session log dialog are well-structured and properly typed.


295-300: LGTM!

Good defensive programming with the directory check and proper error handling. The dependency array is correctly updated.

Also applies to: 323-323


347-374: LGTM!

The handleViewLogs callback is well-implemented with proper state management, error handling, and loading states.


380-398: LGTM!

Good performance optimization using useMemo to prevent unnecessary re-sorting of sessions.


412-412: LGTM!

The increased dialog and scroll area sizes improve the user experience on larger screens.

Also applies to: 440-440


496-543: LGTM!

The session log dialog is well-structured with proper state handling, loading indicators, error messages, and empty state display.

src/components/tabs/custom-files-tab.tsx (4)

10-12: LGTM!

The new imports are properly added for event listening and cross-platform path handling.


41-47: LGTM!

The new state variables are properly destructured from the app store for scan progress tracking.


96-161: LGTM!

The scan function is properly enhanced with progress tracking and cross-platform path handling. The try-finally block ensures proper cleanup.


175-180: LGTM!

Good improvement using path utilities for cross-platform compatibility instead of manual string manipulation.

Also applies to: 294-295

src-tauri/src/minecraft/mod.rs (2)

1-1: LGTM!

The import is correctly added for consistent JSON serialization across the codebase.


347-350: LGTM!

Good consistency improvement using serialize_json_sorted for deterministic JSON output.

src/components/tabs/common/translation-tab.tsx (5)

82-89: LGTM!

The scanProgress prop is well-typed and properly structured for displaying scan progress information.


405-419: LGTM!

Great UX improvements with loading spinners and pulse animations for active operations.


424-424: LGTM!

Consistent and appropriate size adjustments for better user experience on larger screens.

Also applies to: 443-443, 479-479, 492-492, 513-513


558-592: LGTM!

Excellent scan progress visualization with comprehensive information display and smooth animations.


467-467: LGTM!

Nice UI polish with animations and sticky headers for improved user experience.

Also applies to: 473-473, 519-519

src-tauri/src/filesystem.rs (6)

50-59: LGTM! Well-structured progress tracking payload.

The ScanProgressPayload struct is properly designed with appropriate serialization attributes for JavaScript interoperability.


412-547: LGTM! Comprehensive progress tracking implementation.

The function properly tracks progress for both Better Quests file locations and correctly calculates the total file count including the potential DefaultQuests.lang file.


571-639: LGTM! Clean implementation of generic file scanning with progress tracking.

The function properly implements progress tracking and handles extension filtering correctly, including trimming leading dots from the extension parameter.


799-824: LGTM! Well-implemented JSON sorting utilities.

These functions ensure consistent JSON output by recursively sorting object keys, which is important for version control and reproducible builds.


881-885: LGTM! Consistent JSON serialization for language files.

Using serialize_json_sorted ensures language files have consistent key ordering, which is beneficial for version control and file comparison.


71-71: Ensure frontend error parsing supports new prefixed format

I wasn’t able to find any existing handlers that parse error strings like errors.profileDirectoryNotFound:::{dir} in the TypeScript/JavaScript code. Please verify or implement support in the frontend to:

  • Detect and split the error key (e.g. profileDirectoryNotFound) from its parameters
  • Map the key to a user-friendly message (e.g. via your localization system)
  • Display any dynamic parameters (the {dir} value) in the UI

Comment on lines +1 to +28
import { describe, test, expect } from 'bun:test';

describe('Skip Existing Translations E2E - Basic Tests', () => {
test('should have working test framework', () => {
expect(true).toBe(true);
});

test('should handle configuration setting', () => {
const config = {
translation: {
skipExistingTranslations: true
}
};

expect(config.translation.skipExistingTranslations).toBe(true);
});

test('should default to true when skipExistingTranslations is undefined', () => {
const config = {
translation: {
// skipExistingTranslations is undefined
}
};

const skipExisting = config.translation.skipExistingTranslations ?? true;
expect(skipExisting).toBe(true);
});
}); No newline at end of file
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Rename to unit tests and consider adding proper E2E coverage.

These tests are currently basic unit tests rather than end-to-end tests. They validate configuration handling but don't test the actual skip existing translations functionality in a real application context.

Consider the following improvements:

  1. Rename the file to skip-existing-translations.test.ts since these are unit tests
  2. Add proper E2E tests that would test:
    • UI toggle behavior in translation settings
    • Backend API calls to check for existing translations
    • Actual skipping behavior during scan operations
    • Integration with the scanning progress system
-describe('Skip Existing Translations E2E - Basic Tests', () => {
+describe('Skip Existing Translations - Configuration Tests', () => {

For actual E2E testing, you might want to add tests that:

  • Mock the backend translation check commands
  • Test the UI toggle in translation settings
  • Verify that files are actually skipped during scanning
  • Test the interaction with the new scanning progress system
📝 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
import { describe, test, expect } from 'bun:test';
describe('Skip Existing Translations E2E - Basic Tests', () => {
test('should have working test framework', () => {
expect(true).toBe(true);
});
test('should handle configuration setting', () => {
const config = {
translation: {
skipExistingTranslations: true
}
};
expect(config.translation.skipExistingTranslations).toBe(true);
});
test('should default to true when skipExistingTranslations is undefined', () => {
const config = {
translation: {
// skipExistingTranslations is undefined
}
};
const skipExisting = config.translation.skipExistingTranslations ?? true;
expect(skipExisting).toBe(true);
});
});
import { describe, test, expect } from 'bun:test';
describe('Skip Existing Translations - Configuration Tests', () => {
test('should have working test framework', () => {
expect(true).toBe(true);
});
test('should handle configuration setting', () => {
const config = {
translation: {
skipExistingTranslations: true
}
};
expect(config.translation.skipExistingTranslations).toBe(true);
});
test('should default to true when skipExistingTranslations is undefined', () => {
const config = {
translation: {
// skipExistingTranslations is undefined
}
};
const skipExisting = config.translation.skipExistingTranslations ?? true;
expect(skipExisting).toBe(true);
});
});
🤖 Prompt for AI Agents
In src/__tests__/e2e/skip-existing-translations-e2e.test.ts lines 1 to 28, the
current tests are basic unit tests validating configuration but not actual
end-to-end functionality. Rename the file to skip-existing-translations.test.ts
to reflect unit testing. Then create a new E2E test file that covers UI toggle
behavior for skipExistingTranslations, mocks backend API calls to check for
existing translations, verifies that files are skipped during scanning, and
tests integration with the scanning progress system to ensure full end-to-end
coverage.

Comment on lines 14 to 34
/// Validate session ID format: YYYY-MM-DD_HH-MM-SS
fn validate_session_id_format(session_id: &str) -> bool {
if session_id.len() != 19 {
return false;
}

let chars: Vec<char> = session_id.chars().collect();

// Check pattern: YYYY-MM-DD_HH-MM-SS
chars[4] == '-' &&
chars[7] == '-' &&
chars[10] == '_' &&
chars[13] == '-' &&
chars[16] == '-' &&
chars[0..4].iter().all(|c| c.is_ascii_digit()) &&
chars[5..7].iter().all(|c| c.is_ascii_digit()) &&
chars[8..10].iter().all(|c| c.is_ascii_digit()) &&
chars[11..13].iter().all(|c| c.is_ascii_digit()) &&
chars[14..16].iter().all(|c| c.is_ascii_digit()) &&
chars[17..19].iter().all(|c| c.is_ascii_digit())
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve validation function for better maintainability and efficiency.

The function correctly validates the session ID format, but has several areas for improvement:

  1. Efficiency: Converting to Vec<char> for every validation is wasteful for a simple string format check.
  2. Readability: The manual position checking is verbose and error-prone.
  3. Semantic validation: The function doesn't validate actual date/time ranges (e.g., month 13 would pass).

Consider this more efficient and readable implementation:

-/// Validate session ID format: YYYY-MM-DD_HH-MM-SS
-fn validate_session_id_format(session_id: &str) -> bool {
-    if session_id.len() != 19 {
-        return false;
-    }
-    
-    let chars: Vec<char> = session_id.chars().collect();
-    
-    // Check pattern: YYYY-MM-DD_HH-MM-SS
-    chars[4] == '-' && 
-    chars[7] == '-' && 
-    chars[10] == '_' && 
-    chars[13] == '-' && 
-    chars[16] == '-' &&
-    chars[0..4].iter().all(|c| c.is_ascii_digit()) &&
-    chars[5..7].iter().all(|c| c.is_ascii_digit()) &&
-    chars[8..10].iter().all(|c| c.is_ascii_digit()) &&
-    chars[11..13].iter().all(|c| c.is_ascii_digit()) &&
-    chars[14..16].iter().all(|c| c.is_ascii_digit()) &&
-    chars[17..19].iter().all(|c| c.is_ascii_digit())
-}
+/// Validate session ID format: YYYY-MM-DD_HH-MM-SS
+fn validate_session_id_format(session_id: &str) -> bool {
+    if session_id.len() != 19 {
+        return false;
+    }
+    
+    let bytes = session_id.as_bytes();
+    
+    // Check separators at expected positions
+    if bytes[4] != b'-' || bytes[7] != b'-' || bytes[10] != b'_' || 
+       bytes[13] != b'-' || bytes[16] != b'-' {
+        return false;
+    }
+    
+    // Check that all other positions are ASCII digits
+    let digit_ranges = [(0, 4), (5, 7), (8, 10), (11, 13), (14, 16), (17, 19)];
+    digit_ranges.iter().all(|&(start, end)| {
+        bytes[start..end].iter().all(|&b| b.is_ascii_digit())
+    })
+}

Alternative approach using regex (if regex dependency is acceptable):

+use regex::Regex;
+
+/// Validate session ID format: YYYY-MM-DD_HH-MM-SS
+fn validate_session_id_format(session_id: &str) -> bool {
+    static REGEX: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();
+    let regex = REGEX.get_or_init(|| {
+        Regex::new(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$").unwrap()
+    });
+    regex.is_match(session_id)
+}
📝 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
/// Validate session ID format: YYYY-MM-DD_HH-MM-SS
fn validate_session_id_format(session_id: &str) -> bool {
if session_id.len() != 19 {
return false;
}
let chars: Vec<char> = session_id.chars().collect();
// Check pattern: YYYY-MM-DD_HH-MM-SS
chars[4] == '-' &&
chars[7] == '-' &&
chars[10] == '_' &&
chars[13] == '-' &&
chars[16] == '-' &&
chars[0..4].iter().all(|c| c.is_ascii_digit()) &&
chars[5..7].iter().all(|c| c.is_ascii_digit()) &&
chars[8..10].iter().all(|c| c.is_ascii_digit()) &&
chars[11..13].iter().all(|c| c.is_ascii_digit()) &&
chars[14..16].iter().all(|c| c.is_ascii_digit()) &&
chars[17..19].iter().all(|c| c.is_ascii_digit())
}
/// Validate session ID format: YYYY-MM-DD_HH-MM-SS
fn validate_session_id_format(session_id: &str) -> bool {
if session_id.len() != 19 {
return false;
}
let bytes = session_id.as_bytes();
// Check separators at expected positions
if bytes[4] != b'-' || bytes[7] != b'-' || bytes[10] != b'_'
|| bytes[13] != b'-' || bytes[16] != b'-' {
return false;
}
// Check that all other positions are ASCII digits
let digit_ranges = [(0, 4), (5, 7), (8, 10), (11, 13), (14, 16), (17, 19)];
digit_ranges.iter().all(|&(start, end)| {
bytes[start..end].iter().all(|&b| b.is_ascii_digit())
})
}
🤖 Prompt for AI Agents
In src-tauri/src/backup.rs between lines 14 and 34, the
validate_session_id_format function inefficiently converts the input string to a
Vec<char> and manually checks each character position, which is verbose and
error-prone. To fix this, replace the manual checks with a regex pattern that
matches the exact format YYYY-MM-DD_HH-MM-SS, improving readability and
maintainability. Additionally, enhance the function to parse the date and time
components and validate their semantic correctness (e.g., month between 1 and
12, day valid for the month, hour between 0 and 23, etc.) to ensure the session
ID represents a valid datetime.

Apply automatic formatting to ensure consistency with Rust style guidelines
Copy link

@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: 1

🔭 Outside diff range comments (1)
.github/workflows/pr-validation.yml (1)

28-178: Fix YAML formatting issues.

The static analysis tool detected multiple trailing spaces and a missing newline at the end of the file. These formatting issues should be addressed for consistency.

Apply this diff to fix the formatting issues:

-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-      
+      
-          fi
+          fi
+

Remove trailing spaces from all lines and add a newline at the end of the file.

🧹 Nitpick comments (3)
src/lib/types/config.ts (1)

151-151: Consider adding the skipExistingTranslations default to the TRANSLATION_DEFAULTS constant.

The default value true makes sense for performance optimization, but it should be defined in the TRANSLATION_DEFAULTS constant for consistency with other translation configuration defaults.

Apply this change to maintain consistency:

// In src/lib/constants/defaults.ts
export const TRANSLATION_DEFAULTS = {
  modChunkSize: 50,
  questChunkSize: 1,
  guidebookChunkSize: 1,
  resourcePackName: "MinecraftModsLocalizer",
  useTokenBasedChunking: false,
  maxTokensPerChunk: 3000,
  fallbackToEntryBased: true,
  maxEntriesPerChunk: 100,
  contentSplitThreshold: 1000,
  splitPartMaxLength: 800,
  maxFailedChunksRatio: 0.1,
+ skipExistingTranslations: true,
} as const;

Then update the default config to use the constant:

-    skipExistingTranslations: true
+    skipExistingTranslations: TRANSLATION_DEFAULTS.skipExistingTranslations
src/components/ui/translation-history-dialog.tsx (1)

469-473: Simplify the directory path display logic.

The directory path display logic is repetitive and could be simplified for better readability.

Extract the logic into a helper function:

const getDisplayPath = (path: string): string => {
  return path.startsWith('NATIVE_DIALOG:') 
    ? path.substring('NATIVE_DIALOG:'.length)
    : path;
};

// Then use it in the JSX:
<div className="text-sm text-muted-foreground">
  {t('misc.selectedDirectory')} {getDisplayPath(historyDirectory || profileDirectory)}
</div>
src/components/tabs/common/translation-tab.tsx (1)

342-344: Apply the static analysis suggestion for optional chaining

The static analysis tool correctly identifies that this can be simplified using optional chaining for better readability and safety.

Apply this diff to use optional chaining:

-            const actualPath = profileDirectory && profileDirectory.startsWith("NATIVE_DIALOG:")
-                ? profileDirectory.substring("NATIVE_DIALOG:".length)
-                : profileDirectory || "";
+            const actualPath = profileDirectory?.startsWith("NATIVE_DIALOG:")
+                ? profileDirectory.substring("NATIVE_DIALOG:".length)
+                : profileDirectory || "";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9046861 and d4fb54f.

📒 Files selected for processing (16)
  • .github/workflows/pr-validation.yml (3 hunks)
  • src-tauri/src/backup.rs (5 hunks)
  • src-tauri/src/filesystem.rs (15 hunks)
  • src-tauri/src/logging.rs (1 hunks)
  • src/__tests__/e2e/fixtures/output/realistic/complexmod.ja_jp.json (1 hunks)
  • src/__tests__/e2e/fixtures/output/simple/getting_started.ja_jp.snbt (1 hunks)
  • src/__tests__/e2e/fixtures/output/simple/samplemod.ja_jp.json (1 hunks)
  • src/components/settings/path-settings.tsx (0 hunks)
  • src/components/tabs/common/translation-tab.tsx (16 hunks)
  • src/components/tabs/settings-tab.tsx (0 hunks)
  • src/components/ui/translation-history-dialog.tsx (11 hunks)
  • src/lib/constants/defaults.ts (2 hunks)
  • src/lib/services/config-service.ts (3 hunks)
  • src/lib/services/translation-runner.ts (1 hunks)
  • src/lib/store/index.ts (4 hunks)
  • src/lib/types/config.ts (2 hunks)
💤 Files with no reviewable changes (2)
  • src/components/tabs/settings-tab.tsx
  • src/components/settings/path-settings.tsx
✅ Files skipped from review due to trivial changes (3)
  • src/tests/e2e/fixtures/output/simple/samplemod.ja_jp.json
  • src/tests/e2e/fixtures/output/realistic/complexmod.ja_jp.json
  • src/tests/e2e/fixtures/output/simple/getting_started.ja_jp.snbt
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/lib/constants/defaults.ts
  • src-tauri/src/backup.rs
  • src-tauri/src/logging.rs
  • src/lib/store/index.ts
  • src-tauri/src/filesystem.rs
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/lib/types/config.ts (1)
src/lib/constants/defaults.ts (1)
  • TRANSLATION_DEFAULTS (36-48)
src/components/ui/translation-history-dialog.tsx (6)
src/components/ui/button.tsx (1)
  • Button (59-59)
src/lib/i18n.ts (1)
  • useAppTranslation (46-49)
src/lib/store/index.ts (1)
  • useAppStore (120-444)
src/lib/services/file-service.ts (1)
  • FileService (188-382)
src/components/ui/dialog.tsx (5)
  • DialogContent (127-127)
  • DialogHeader (130-130)
  • DialogTitle (133-133)
  • Dialog (125-125)
  • DialogFooter (129-129)
src/components/ui/scroll-area.tsx (1)
  • ScrollArea (68-68)
src/lib/services/config-service.ts (1)
src/lib/types/config.ts (1)
  • DEFAULT_CONFIG (126-159)
🪛 YAMLlint (1.37.1)
.github/workflows/pr-validation.yml

[error] 28-28: trailing spaces

(trailing-spaces)


[error] 31-31: trailing spaces

(trailing-spaces)


[error] 34-34: trailing spaces

(trailing-spaces)


[error] 37-37: trailing spaces

(trailing-spaces)


[error] 40-40: trailing spaces

(trailing-spaces)


[error] 43-43: trailing spaces

(trailing-spaces)


[error] 48-48: trailing spaces

(trailing-spaces)


[error] 51-51: trailing spaces

(trailing-spaces)


[error] 66-66: trailing spaces

(trailing-spaces)


[error] 71-71: trailing spaces

(trailing-spaces)


[error] 84-84: trailing spaces

(trailing-spaces)


[error] 89-89: trailing spaces

(trailing-spaces)


[error] 92-92: trailing spaces

(trailing-spaces)


[error] 95-95: trailing spaces

(trailing-spaces)


[error] 98-98: trailing spaces

(trailing-spaces)


[error] 108-108: trailing spaces

(trailing-spaces)


[error] 113-113: trailing spaces

(trailing-spaces)


[error] 116-116: trailing spaces

(trailing-spaces)


[error] 131-131: trailing spaces

(trailing-spaces)


[error] 136-136: trailing spaces

(trailing-spaces)


[error] 139-139: trailing spaces

(trailing-spaces)


[error] 145-145: trailing spaces

(trailing-spaces)


[error] 156-156: trailing spaces

(trailing-spaces)


[error] 161-161: trailing spaces

(trailing-spaces)


[error] 164-164: trailing spaces

(trailing-spaces)


[error] 169-169: trailing spaces

(trailing-spaces)


[error] 172-172: trailing spaces

(trailing-spaces)


[error] 178-178: no new line character at the end of file

(new-line-at-end-of-file)

🪛 Biome (1.9.4)
src/components/tabs/common/translation-tab.tsx

[error] 342-342: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/lib/services/config-service.ts

[error] 154-154: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 154-154: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

⏰ 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: Build - aarch64-apple-darwin
  • GitHub Check: Build - x86_64-apple-darwin
  • GitHub Check: Build - x86_64-unknown-linux-gnu
  • GitHub Check: Build - x86_64-pc-windows-msvc
  • GitHub Check: Security Scan
  • GitHub Check: Backend Tests
🔇 Additional comments (29)
src/lib/types/config.ts (1)

97-98: Good addition of the skipExistingTranslations feature flag.

This new optional property provides users with control over whether to skip files that already have existing translations, which can significantly improve performance during translation operations.

.github/workflows/pr-validation.yml (1)

8-60: Excellent workflow restructuring for better separation of concerns.

The split into separate jobs (frontend-tests, backend-tests, integration-tests, security-scan) improves maintainability and allows for parallel execution. The caching strategy is also well-implemented.

src/lib/services/translation-runner.ts (1)

160-163: LGTM! Proper migration to shared profile directory system.

The change from config.paths.minecraftDir to useAppStore.getState().profileDirectory aligns with the PR's objective of removing path settings and using a shared profile directory system. The fallback to empty string and maintaining the minecraftDir key for backend compatibility is appropriate.

src/lib/services/config-service.ts (2)

154-154: Correct fix for static method invocation.

The change from this.migrateApiKeys(this.config) to ConfigService.migrateApiKeys(this.config) is correct since migrateApiKeys is a static method. This fixes the static analysis warning about using this in a static context.


398-400: Good addition of update configuration handling.

Adding the update configuration with checkOnStartup provides proper handling for update-related settings in the config conversion process.

src/components/ui/translation-history-dialog.tsx (6)

3-3: Good addition of necessary imports for new functionality.

The new imports (useMemo, FileText, FolderOpen, FileService) are appropriate for the enhanced session log viewing and directory selection features.

Also applies to: 8-8, 12-12


284-289: Well-structured state management for session log dialog.

The state variables for managing the session log dialog are properly named and initialized. The separation of concerns between loading, error, and content states is good.


344-365: Excellent directory selection implementation with proper error handling.

The directory selection handler includes proper validation, error handling, and automatic session reloading. The user experience is well thought out.


383-415: Comprehensive session log viewing implementation.

The session log viewing functionality is well-implemented with proper loading states, error handling, and fallback logic for directory selection. The async handling is appropriate.


422-440: Good use of useMemo for performance optimization.

The memoization of the sorted sessions prevents unnecessary re-computations and improves performance. The sorting logic is clean and handles all the required fields.


560-607: Well-structured session log dialog with proper UX.

The session log dialog provides a good user experience with loading states, error handling, and proper content display. The scrollable pre-formatted content is appropriate for log viewing.

src/components/tabs/common/translation-tab.tsx (18)

21-22: LGTM: Good addition of necessary imports

The addition of useAppStore and toast imports aligns well with the new shared state management and enhanced error handling functionality.


84-92: LGTM: Well-designed scan progress interface

The optional scanProgress prop provides a clean interface for tracking scan progress with all necessary fields for displaying current file, counts, and scan type.


158-160: LGTM: Proper integration with shared state

The migration from local state to shared profileDirectory state from the global store is correctly implemented and will improve consistency across tabs.


173-177: LGTM: Good input validation

The directory path validation with proper error handling ensures invalid selections are caught early with appropriate user feedback.


199-204: LGTM: Enhanced error handling with toast notifications

The improved error handling combines both component state updates and toast notifications for better user experience, with proper error message extraction.


209-213: LGTM: Proper validation before scanning

The validation ensures a profile directory is selected before attempting to scan, with appropriate error messages and toast notifications.


224-229: LGTM: Smart UI optimization with requestAnimationFrame

Using requestAnimationFrame to defer UI clearing operations prevents blocking the main thread during scanning operations, improving responsiveness.


234-247: LGTM: Sophisticated error message parsing

The error handling logic properly handles both translation keys with path parameters and regular error messages, providing contextual feedback to users.


420-428: LGTM: Enhanced button states with loading indicators

The scan button improvements with loading spinner, pulse animation, and proper disabled states provide excellent user feedback during operations.


432-438: LGTM: Consistent loading indicators

The translate button follows the same pattern as the scan button with appropriate loading states and animations.


441-441: LGTM: Responsive design improvement

The responsive width classes ensure the target language selector adapts properly to different screen sizes.


460-460: LGTM: Consistent responsive design

The search input follows the same responsive design pattern as other components.


475-481: LGTM: Proper directory path display

The directory display correctly handles the NATIVE_DIALOG prefix removal for clean user presentation.


484-487: LGTM: Animated error messages

The error message styling with fade-in and slide-in animations provides smooth visual feedback.


490-527: LGTM: Enhanced translation progress display

The translation progress section with dual progress bars (individual and overall) provides comprehensive feedback during translation operations.


530-532: LGTM: Improved table container

The ScrollArea with both orientations and responsive height constraints provides better table handling across different screen sizes.


575-610: LGTM: Comprehensive scan progress UI

The scanning progress display with file information, counts, percentage, and progress bar provides excellent user feedback during scan operations. The responsive design and animations enhance the user experience.


657-657: LGTM: Staggered animation for table rows

The table row animations with staggered delays create a smooth, professional appearance when results are displayed.

Comment on lines +305 to +307
const actualPath = minecraftDir.startsWith('NATIVE_DIALOG:')
? minecraftDir.substring('NATIVE_DIALOG:'.length)
: minecraftDir;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Extract NATIVE_DIALOG prefix handling into a utility function.

The NATIVE_DIALOG: prefix stripping logic is repeated in multiple places. This should be extracted into a reusable utility function to avoid code duplication.

Create a utility function:

// Add to src/lib/utils/path-utils.ts or similar
export const extractActualPath = (path: string): string => {
  return path.startsWith('NATIVE_DIALOG:') 
    ? path.substring('NATIVE_DIALOG:'.length)
    : path;
};

Then replace the repeated logic:

-      // Extract the actual path if it has the NATIVE_DIALOG prefix
-      const actualPath = minecraftDir.startsWith('NATIVE_DIALOG:')
-        ? minecraftDir.substring('NATIVE_DIALOG:'.length)
-        : minecraftDir;
+      const actualPath = extractActualPath(minecraftDir);

Also applies to: 400-402

🤖 Prompt for AI Agents
In src/components/ui/translation-history-dialog.tsx around lines 305 to 307 and
also lines 400 to 402, the logic to strip the 'NATIVE_DIALOG:' prefix from paths
is duplicated. Extract this logic into a utility function named
extractActualPath in a new or existing file like src/lib/utils/path-utils.ts.
Replace the inline prefix stripping code with calls to this new utility function
to remove duplication and improve maintainability.

- Set main layout container max width to 1600px on 2xl screens
- Add xl breakpoint with max-w-6xl for better responsive scaling
- Limit translation history dialog to 1600px max width on large screens
- Reduce dialog width from 95vw to 90vw for better margins
Copy link

@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)
src/components/ui/translation-history-dialog.tsx (2)

305-307: Extract NATIVE_DIALOG prefix handling into a utility function.

The NATIVE_DIALOG: prefix stripping logic is duplicated in multiple places. This should be extracted into a reusable utility function to avoid code duplication.

Create a utility function:

// Add to src/lib/utils/path-utils.ts or similar
export const extractActualPath = (path: string): string => {
  return path.startsWith('NATIVE_DIALOG:') 
    ? path.substring('NATIVE_DIALOG:'.length)
    : path;
};

Then replace the repeated logic:

-      // Extract the actual path if it has the NATIVE_DIALOG prefix
-      const actualPath = minecraftDir.startsWith('NATIVE_DIALOG:')
-        ? minecraftDir.substring('NATIVE_DIALOG:'.length)
-        : minecraftDir;
+      const actualPath = extractActualPath(minecraftDir);

400-402: Extract NATIVE_DIALOG prefix handling into a utility function.

The NATIVE_DIALOG: prefix stripping logic is duplicated in multiple places. This should be extracted into a reusable utility function to avoid code duplication.

Create a utility function:

// Add to src/lib/utils/path-utils.ts or similar
export const extractActualPath = (path: string): string => {
  return path.startsWith('NATIVE_DIALOG:') 
    ? path.substring('NATIVE_DIALOG:'.length)
    : path;
};

Then replace the repeated logic:

-      // Extract the actual path if it has the NATIVE_DIALOG prefix
-      const actualPath = minecraftDir.startsWith('NATIVE_DIALOG:')
-        ? minecraftDir.substring('NATIVE_DIALOG:'.length)
-        : minecraftDir;
+      const actualPath = extractActualPath(minecraftDir);
🧹 Nitpick comments (1)
src/components/ui/translation-history-dialog.tsx (1)

90-90: Enhance type safety by adding proper prop types.

The component prop interface should be more explicitly defined for better type safety.

-function SessionDetailsRow({ sessionSummary, onViewLogs }: { sessionSummary: SessionSummary; onViewLogs: (sessionId: string) => void }) {
+interface SessionDetailsRowProps {
+  sessionSummary: SessionSummary;
+  onViewLogs: (sessionId: string) => void;
+}
+
+function SessionDetailsRow({ sessionSummary, onViewLogs }: SessionDetailsRowProps) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4fb54f and f726f5f.

📒 Files selected for processing (2)
  • src/components/layout/main-layout.tsx (1 hunks)
  • src/components/ui/translation-history-dialog.tsx (11 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/layout/main-layout.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/ui/translation-history-dialog.tsx (6)
src/components/ui/button.tsx (1)
  • Button (59-59)
src/lib/i18n.ts (1)
  • useAppTranslation (46-49)
src/lib/store/index.ts (1)
  • useAppStore (120-444)
src/lib/services/file-service.ts (1)
  • FileService (188-382)
src/components/ui/dialog.tsx (5)
  • DialogContent (127-127)
  • DialogHeader (130-130)
  • DialogTitle (133-133)
  • Dialog (125-125)
  • DialogFooter (129-129)
src/components/ui/scroll-area.tsx (1)
  • ScrollArea (68-68)
⏰ 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: Build - x86_64-apple-darwin
  • GitHub Check: Build - x86_64-pc-windows-msvc
  • GitHub Check: Build - aarch64-apple-darwin
  • GitHub Check: Build - x86_64-unknown-linux-gnu
  • GitHub Check: Security Scan
  • GitHub Check: Backend Tests
🔇 Additional comments (16)
src/components/ui/translation-history-dialog.tsx (16)

3-3: Good addition of useMemo import for performance optimization.

The addition of useMemo import is appropriate for optimizing the session sorting performance.


8-8: Approve new icon imports for enhanced UI.

The new FileText and FolderOpen icons are appropriately imported and will enhance the user interface for the new features.


12-12: Good integration of FileService for directory selection.

The FileService import is correctly added to support the new directory selection functionality.


133-144: Well-implemented View Logs button with proper accessibility.

The View Logs button implementation is well-structured with proper icon placement, accessibility features, and clear user interaction patterns.


175-181: Good prop interface expansion for SessionRow.

The addition of the onViewLogs prop to the SessionRow component is implemented correctly and maintains type safety.


271-271: Proper callback propagation in SessionDetailsRow.

The onViewLogs callback is correctly passed to the SessionDetailsRow component.


279-279: Correct usage of app store for profile directory.

The integration with the app store to retrieve the profile directory is implemented correctly.


284-289: Well-structured state management for session log dialog.

The new state variables for managing the session log dialog are appropriately initialized and follow React best practices.


343-365: Robust directory selection implementation with proper error handling.

The directory selection functionality is well-implemented with proper validation, error handling, and user feedback. The automatic session reload after directory selection provides good UX.


383-415: Comprehensive session log viewing functionality.

The handleViewLogs function is well-implemented with proper error handling, loading states, and fallback directory logic. The async implementation follows React best practices.


422-440: Excellent performance optimization with useMemo.

The session sorting is properly memoized to avoid unnecessary re-computations. The sorting logic is comprehensive and handles all relevant fields correctly.


454-454: Good responsive design improvements.

The dialog sizing improvements for larger screens (2xl breakpoint) provide better user experience on different screen sizes.


456-476: Well-structured directory selection UI.

The directory selection UI is well-implemented with proper button styling, icon placement, and directory path display with prefix handling.


502-502: Improved scroll area sizing for better responsiveness.

The scroll area height adjustments for different screen sizes provide better user experience across devices.


530-532: Consistent directory path handling with prefix extraction.

The directory path handling in the SessionRow component correctly extracts the actual path from the NATIVE_DIALOG prefix.


560-607: Comprehensive session log dialog implementation.

The session log dialog is well-implemented with proper loading states, error handling, and content display. The UI structure follows consistent patterns with the main dialog.

Update format strings to use inline arguments to comply with Clippy's
uninlined_format_args lint. This fixes the failing Backend Tests job
in CI by addressing all format\! macro calls that were using the older
"{}", var syntax instead of the newer "{var}" syntax.

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

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

@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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f726f5f and 88c3398.

📒 Files selected for processing (2)
  • src-tauri/src/filesystem.rs (15 hunks)
  • src-tauri/src/minecraft/mod.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src-tauri/src/minecraft/mod.rs
⏰ 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: Build - x86_64-apple-darwin
  • GitHub Check: Build - aarch64-apple-darwin
  • GitHub Check: Build - x86_64-unknown-linux-gnu
  • GitHub Check: Build - x86_64-pc-windows-msvc
  • GitHub Check: Security Scan
  • GitHub Check: Backend Tests
🔇 Additional comments (9)
src-tauri/src/filesystem.rs (9)

5-6: New imports for progress tracking look good.

The additions of Duration, Instant for timing control and Emitter for event emission are appropriate for the new progress tracking functionality.


50-59: Well-structured progress payload.

The ScanProgressPayload struct provides all necessary fields for comprehensive progress tracking. The optional total_count field allows flexibility for scenarios where the total might not be known upfront.


89-101: Good practice: Count files upfront for accurate progress tracking.

Pre-counting the total files before scanning allows for accurate progress percentage calculations. The 200ms emit interval strikes a good balance between responsiveness and performance.


118-137: Intelligent progress emission logic.

The condition processed_count % 10 == 0 || last_emit.elapsed() >= EMIT_INTERVAL || entry_path.extension().is_some_and(|ext| ext == "jar") is well-designed:

  • Every 10 files for consistent updates
  • Time-based updates every 200ms for responsiveness
  • Immediate updates when finding JAR files for user feedback

This provides good UX without overwhelming the event system.


147-158: Consistent completion event emission.

The completion event with completed: true and empty current_file provides a clear signal to the frontend that scanning is finished.


273-283: Progress tracking properly integrated into FTB quest scanning.

The same pattern is consistently applied across all scanning functions, which is good for maintainability. The progress tracking is correctly scoped within each quest directory loop.


797-822: Excellent JSON serialization utilities.

The recursive sort_json_object function and serialize_json_sorted wrapper provide consistent JSON output formatting. The implementation correctly handles nested objects and arrays.


879-883: Consistent use of sorted JSON serialization.

The write_lang_file function correctly uses the new serialize_json_sorted utility, ensuring consistent JSON output across the application.


64-64: Ignore app_handle in frontend invocations

Tauri injects the app_handle automatically into Rust commands, so frontend calls to invoke (and your FileService.invoke wrapper) should continue passing only the payload object. No changes are needed in your TS/JS files or tests—in all cases we only see calls like:

FileService.invoke('get_mod_files', { dir: '/some/path' });

which remain correct. Please disregard the earlier suggestion to add an app_handle argument in frontend code.

Likely an incorrect or invalid review comment.

Comment on lines +412 to +428
// Count total files first for progress tracking
let total_files = if better_quests_dir.exists() && better_quests_dir.is_dir() {
WalkDir::new(&better_quests_dir)
.max_depth(1)
.into_iter()
.filter_map(|e| e.ok())
.filter(|entry| entry.path().is_file())
.count()
} else {
0
} + 1; // +1 for the potential DefaultQuests.lang file

// Progress tracking
let mut processed_count = 0;
let mut last_emit = Instant::now();
const EMIT_INTERVAL: Duration = Duration::from_millis(200);

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Verify the total file count calculation for Better Quests.

The total file count calculation adds 1 for the potential DefaultQuests.lang file regardless of whether it exists. This could lead to inaccurate progress percentages if the file doesn't exist.

Consider checking if the file exists before adding it to the count:

-    } + 1; // +1 for the potential DefaultQuests.lang file
+    } + if path.join("config").join("betterquesting").join("DefaultQuests.lang").exists() { 1 } else { 0 };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src-tauri/src/filesystem.rs around lines 412 to 428, the total file count for
Better Quests always adds 1 for the potential DefaultQuests.lang file without
verifying its existence, which can cause inaccurate progress tracking. Modify
the code to check if DefaultQuests.lang actually exists before adding 1 to the
total file count. This ensures the total_files variable accurately reflects the
real number of files to process.

let path = Path::new(dir);
if !path.exists() || !path.is_dir() {
return Err(format!("Directory not found: {dir}"));
return Err(format!("errors.profileDirectoryNotFound:::{dir}"));
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify error message format consistency across the codebase.

The error messages now use a prefixed format like "errors.profileDirectoryNotFound:::{dir}". This appears to be for internationalization purposes, but ensure that the frontend properly handles this new format.

Also applies to: 176-176, 182-182, 402-402, 565-565


🏁 Script executed:

#!/bin/bash
# Description: Check how these prefixed error messages are handled in the frontend
# Expected: Find error handling code that processes the "errors." prefix format

# Search for error handling patterns in frontend code
rg -A 3 -B 3 "errors\." --type=tsx --type=ts --type=js

# Also check for the specific error keys in localization files
rg "profileDirectoryNotFound|questsDirectoryNotFound|guidebooksDirectoryNotFound|customFilesDirectoryNotFound" --type=json

Length of output: 1461


Inconsistent error message format: add front-end parsing or simplify backend output

The Rust code in src-tauri/src/filesystem.rs (lines 71, 176, 182, 402, 565) now returns errors as:

Err(format!("errors.profileDirectoryNotFound:::{dir}"))

but your localization files define flat keys ("profileDirectoryNotFound") under common.json (no nested errors object), and there’s no existing front-end logic to:

  • strip the errors. prefix,
  • split on ::: to extract the translation key vs. the path,
  • call t(translationKey, { path }).

As a result, lookups for "errors.profileDirectoryNotFound" will fail, and the raw string (including :::) will be displayed.

To fix this, choose one of:

  • Simplify backend output: return just the key and parameters (e.g. ("profileDirectoryNotFound", dir) or format!("profileDirectoryNotFound:::{dir}")), and let the front-end split/use it.
  • Implement front-end parsing: before rendering errors, split on :::; remove the errors. prefix; then call t(key, { path }).

Affected backend locations:

  • src-tauri/src/filesystem.rs: lines 71, 176, 182, 402, 565

Please adjust accordingly so translation lookups succeed.

🤖 Prompt for AI Agents
In src-tauri/src/filesystem.rs at lines 71, 176, 182, 402, and 565, the error
messages include a prefix "errors." and use a ::: separator which does not match
the flat translation keys in the front-end localization files. To fix this,
modify the backend error returns to only include the translation key without the
"errors." prefix, for example return "profileDirectoryNotFound:::{dir}" instead
of "errors.profileDirectoryNotFound:::{dir}". This will align the backend output
with the front-end keys and enable correct translation lookups without requiring
front-end parsing changes.

@Y-RyuZU Y-RyuZU merged commit 3a54d4d into main Jul 17, 2025
11 checks passed
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.

2 participants