• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

agentic-dev-library / thumbcode / 21935184468

12 Feb 2026 05:47AM UTC coverage: 42.344% (+0.08%) from 42.263%
21935184468

Pull #127

github

web-flow
Merge 9b8bc04da into 8a2dd33e7
Pull Request #127: refactor: decompose 8 large files into focused components

751 of 2374 branches covered (31.63%)

Branch coverage included in aggregate %.

18 of 103 new or added lines in 19 files covered. (17.48%)

50 existing lines in 3 files now uncovered.

1619 of 3223 relevant lines covered (50.23%)

19.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/components/code/FileTree.tsx
1
/**
2
 * FileTree Component
3
 *
4
 * Displays a hierarchical file/folder structure.
5
 * Supports expandable folders and file type icons.
6
 * Uses paint daube icons for brand consistency.
7
 */
8

9
import { useMemo, useState } from 'react';
10
import { View } from 'react-native';
11
import { organicBorderRadius } from '@/lib/organic-styles';
12
import { TreeNode } from './TreeNode';
13

14
export interface FileNode {
15
  name: string;
16
  type: 'file' | 'folder';
17
  path: string;
18
  children?: FileNode[];
19
  modified?: boolean;
20
  added?: boolean;
21
  deleted?: boolean;
22
}
23

24
interface FileTreeProps {
25
  /** Root nodes of the tree */
26
  data: FileNode[];
27
  /** Callback when a file is selected */
28
  onSelectFile?: (path: string) => void;
29
  /** Currently selected file path */
30
  selectedPath?: string;
31
  /** Initially expanded folders */
32
  defaultExpanded?: string[];
33
  /** Show file status indicators */
34
  showStatus?: boolean;
35
}
36

37
export function FileTree({
38
  data,
39
  onSelectFile,
40
  selectedPath,
41
  defaultExpanded = [],
×
42
  showStatus = true,
×
43
}: Readonly<FileTreeProps>) {
44
  const [expandedPaths, setExpandedPaths] = useState<Set<string>>(new Set(defaultExpanded));
×
45

46
  const toggleExpanded = (path: string) => {
×
47
    setExpandedPaths((prev) => {
×
48
      const next = new Set(prev);
×
49
      if (next.has(path)) {
×
50
        next.delete(path);
×
51
      } else {
52
        next.add(path);
×
53
      }
54
      return next;
×
55
    });
56
  };
57

58
  // Sort nodes: folders first, then alphabetically
59
  const sortedData = useMemo(() => {
×
60
    const sortNodes = (nodes: FileNode[]): FileNode[] => {
×
61
      return [...nodes]
×
62
        .sort((a, b) => {
63
          if (a.type !== b.type) {
×
64
            return a.type === 'folder' ? -1 : 1;
×
65
          }
66
          return a.name.localeCompare(b.name);
×
67
        })
68
        .map((node) => ({
×
69
          ...node,
70
          children: node.children ? sortNodes(node.children) : undefined,
×
71
        }));
72
    };
73
    return sortNodes(data);
×
74
  }, [data]);
75

76
  return (
×
77
    <View
78
      accessibilityRole="list"
79
      accessibilityLabel="File tree"
80
      className="bg-surface overflow-hidden"
81
      style={organicBorderRadius.card}
82
    >
83
      {sortedData.map((node) => (
NEW
84
        <TreeNode
×
85
          key={node.path}
86
          node={node}
87
          depth={0}
88
          onSelectFile={onSelectFile}
89
          selectedPath={selectedPath}
90
          expandedPaths={expandedPaths}
91
          toggleExpanded={toggleExpanded}
92
          showStatus={showStatus}
93
        />
94
      ))}
95
    </View>
96
  );
97
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc