Skip to content

Refactor/board view folder structure#114

Merged
webdevcody merged 5 commits intomainfrom
refactor/board-view-folder-structure
Dec 16, 2025
Merged

Refactor/board view folder structure#114
webdevcody merged 5 commits intomainfrom
refactor/board-view-folder-structure

Conversation

@Shironex
Copy link
Collaborator

  • Refactor the board view (3,600+ lines) into a better folder structure
  • Add folder-pattern.md to standardize the project structure

Shironex and others added 5 commits December 15, 2025 23:34
- Extract board-view into organized subfolders following new pattern:
  - components/: kanban-card, kanban-column
  - dialogs/: all dialog and modal components (8 files)
  - hooks/: all board-specific hooks (10 files)
  - shared/: reusable components between dialogs (model-selector, etc.)
- Rename all files to kebab-case convention
- Add barrel exports (index.ts) for clean imports
- Add docs/folder-pattern.md documenting the folder structure
- Reduce board-view.tsx from ~3600 lines to ~490 lines

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@Shironex Shironex self-assigned this Dec 16, 2025
@Shironex Shironex added Refactor A complete logic rewrite is requested or being performed for an issue. Do Not Merge Use this label if something should not be merged. labels Dec 16, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Shironex, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request undertakes a significant architectural improvement by refactoring the core board-view component into a highly modular and organized structure. The primary goal is to enhance code maintainability, readability, and scalability by breaking down a large, complex file into smaller, domain-specific components, hooks, and dialogs. This change also introduces documentation for standardized folder patterns and identifies future refactoring opportunities, laying a strong foundation for continued development and code quality.

Highlights

  • Major Refactoring of Board View: The monolithic board-view.tsx file (over 3,600 lines) has been extensively refactored into a modular folder structure, breaking it down into smaller, more manageable components, dialogs, and hooks.
  • Standardized Folder Pattern: A new folder-pattern.md document has been introduced to standardize the project's folder structure and naming conventions, promoting consistency and maintainability across the codebase.
  • New Refactoring Candidates Document: A REFACTORING_CANDIDATES.md file was added, identifying other large files (1000+ lines) that require future refactoring, demonstrating a proactive approach to code health.
  • Enhanced Board Functionality Modularity: Key functionalities of the board view, such as controls, header, search bar, drag-and-drop logic, feature actions, and persistence, are now encapsulated in dedicated components and custom hooks.
  • Improved Dialog and Modal Organization: All dialogs and modals specific to the board view, including add/edit feature, agent output, completed features, and follow-up prompts, have been moved into a dedicated dialogs subfolder for better organization.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an excellent and much-needed refactoring of the massive board-view.tsx component. Breaking it down into a well-structured folder with components, hooks, and dialogs greatly improves maintainability and readability. The addition of folder-pattern.md is a fantastic step towards standardizing the codebase. My review includes a critical security concern and several suggestions for improving efficiency, correctness, and consistency in the new hooks.

"allow": [
"Bash(dir \"C:\\Users\\Ben\\Desktop\\appdev\\git\\automaker\\apps\\app\\public\")"
"Bash(dir \"C:\\Users\\Ben\\Desktop\\appdev\\git\\automaker\\apps\\app\\public\")",
"Bash(find:*)"
Copy link
Contributor

Choose a reason for hiding this comment

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

security-critical critical

The permission Bash(find:*) is overly permissive and poses a security risk. It allows the find command to run on any directory on the system, which could be exploited. Please scope this permission to only the necessary directories or remove it if it's not essential.

Comment on lines +28 to +32
if (
e.key === "/" &&
!(e.target instanceof HTMLInputElement) &&
!(e.target instanceof HTMLTextAreaElement)
) {
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The check for focused input elements is not comprehensive. It misses other input-like elements, such as those with contenteditable="true". This could lead to the search bar being focused unexpectedly when the user is typing in another part of the UI. A more robust check should be used to prevent this.

Suggested change
if (
e.key === "/" &&
!(e.target instanceof HTMLInputElement) &&
!(e.target instanceof HTMLTextAreaElement)
) {
if (
e.key === "/" &&
!(e.target instanceof HTMLInputElement) &&
!(e.target instanceof HTMLTextAreaElement) &&
!(e.target as HTMLElement).isContentEditable
) {

Comment on lines +125 to +139
if (feature.imagePaths && feature.imagePaths.length > 0) {
try {
const api = getElectronAPI();
for (const imagePathObj of feature.imagePaths) {
try {
await api.deleteFile(imagePathObj.path);
console.log(`[Board] Deleted image: ${imagePathObj.path}`);
} catch (error) {
console.error(`[Board] Failed to delete image ${imagePathObj.path}:`, error);
}
}
} catch (error) {
console.error(`[Board] Error deleting images for feature ${featureId}:`, error);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The image deletion logic uses await inside a for...of loop, which processes deletions sequentially. For better performance, especially with multiple images, these deletions can be parallelized using Promise.all.

      if (feature.imagePaths && feature.imagePaths.length > 0) {
        try {
          const api = getElectronAPI();
          const deletePromises = feature.imagePaths.map((imagePathObj) =>
            api.deleteFile(imagePathObj.path).catch((error) => {
              console.error(
                `[Board] Failed to delete image ${imagePathObj.path}:`,
                error
              );
            })
          );
          await Promise.all(deletePromises);
        } catch (error) {
          console.error(
            `[Board] Error setting up image deletion for feature ${featureId}:`,
            error
          );
        }
      }

Comment on lines +575 to +597
const handleDeleteAllVerified = useCallback(async () => {
const verifiedFeatures = features.filter((f) => f.status === "verified");

for (const feature of verifiedFeatures) {
const isRunning = runningAutoTasks.includes(feature.id);
if (isRunning) {
try {
await autoMode.stopFeature(feature.id);
} catch (error) {
console.error(
"[Board] Error stopping feature before delete:",
error
);
}
}
removeFeature(feature.id);
persistFeatureDelete(feature.id);
}

toast.success("All verified features deleted", {
description: `Deleted ${verifiedFeatures.length} feature(s).`,
});
}, [features, runningAutoTasks, autoMode, removeFeature, persistFeatureDelete]);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The handleDeleteAllVerified function processes feature deletions sequentially inside a loop. This can be slow if there are many features to delete. The operations can be parallelized for better performance by first stopping all running features and then deleting them.

  const handleDeleteAllVerified = useCallback(async () => {
    const verifiedFeatures = features.filter((f) => f.status === "verified");
    if (verifiedFeatures.length === 0) return;

    const featuresToStop = verifiedFeatures.filter((feature) =>
      runningAutoTasks.includes(feature.id)
    );

    if (featuresToStop.length > 0) {
      await Promise.all(
        featuresToStop.map((feature) =>
          autoMode.stopFeature(feature.id).catch((error) => {
            console.error(
              `[Board] Error stopping feature ${feature.id} before delete:`,
              error
            );
          })
        )
      );
    }

    const deletePromises = verifiedFeatures.map((feature) => {
      removeFeature(feature.id);
      return persistFeatureDelete(feature.id);
    });

    await Promise.all(deletePromises);

    toast.success("All verified features deleted", {
      description: `Deleted ${verifiedFeatures.length} feature(s).`,
    });
  }, [features, runningAutoTasks, autoMode, removeFeature, persistFeatureDelete]);

const featuresWithIds = result.features.map(
(f: any, index: number) => ({
...f,
id: f.id || `feature-${index}-${Date.now()}`,
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The fallback ID generation feature-${index}-${Date.now()} might not be sufficiently unique. If multiple features are loaded in the same millisecond, they could get the same ID, leading to issues with React keys and state management. Using Math.random() would provide better uniqueness.

Suggested change
id: f.id || `feature-${index}-${Date.now()}`,
id: f.id || `feature-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,

Comment on lines +207 to +212
if (!muteDoneSound) {
const audio = new Audio("/sounds/ding.mp3");
audio
.play()
.catch((err) => console.warn("Could not play ding sound:", err));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

A new Audio object is created every time a feature completion event is handled. This is inefficient. The Audio object should be created once and reused. Consider creating it once inside the useEffect but outside the event handler.

Comment on lines +118 to +121
description: `Manually verified: ${draggedFeature.description.slice(
0,
50
)}${draggedFeature.description.length > 50 ? "..." : ""}`,
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This file manually truncates description strings for toast messages. A new utility function truncateDescription has been added in apps/app/src/lib/utils.ts for this purpose. Using this utility will ensure consistency across the application. This applies to multiple toast messages in this file.

You'll need to import it: import { truncateDescription } from "@/lib/utils";

            description: `Manually verified: ${truncateDescription(draggedFeature.description)}`,

@webdevcody webdevcody marked this pull request as ready for review December 16, 2025 02:51
@webdevcody webdevcody merged commit 676169b into main Dec 16, 2025
3 checks passed
@webdevcody webdevcody deleted the refactor/board-view-folder-structure branch December 16, 2025 02:51
@Shironex Shironex added Ready-To-Merge A feature or bug has been improved/fixed and a final review is requested before merging. and removed Do Not Merge Use this label if something should not be merged. labels Dec 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready-To-Merge A feature or bug has been improved/fixed and a final review is requested before merging. Refactor A complete logic rewrite is requested or being performed for an issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants