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

jcubic / 10xDevs / 18619660514

18 Oct 2025 06:52PM UTC coverage: 19.299% (-2.7%) from 21.953%
18619660514

push

github

jcubic
improve performance

77 of 110 branches covered (70.0%)

Branch coverage included in aggregate %.

35 of 162 new or added lines in 4 files covered. (21.6%)

189 existing lines in 8 files now uncovered.

468 of 2714 relevant lines covered (17.24%)

2.69 hits per line

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

85.11
/src/components/notes/LeftPanel.tsx
1
'use client';
2

3
import { useState, useMemo, memo, useCallback } from 'react';
1✔
4
import { Box, Button, Input, Stack, Text } from '@chakra-ui/react';
1✔
5
import type { NoteTreeNode, TreeNode } from '@/types/tree';
6

7
import TreeView from '@/components/TreeView';
1✔
8
import { ConfirmationDialog } from '@/components/ui/confirmation-dialog';
1✔
9

10
interface LeftPanelProps {
11
  notes: NoteTreeNode[];
12
  selectedNoteId: number | null;
13
  onNoteSelect: (id: number) => void;
14
  onNewNote: () => void;
15
  onDeleteNote: (id: number) => void;
16
  onRenameNote: (id: number, name: string) => Promise<void>;
17
}
18

19
const LeftPanel = memo(function LeftPanel({
1✔
20
  notes,
6✔
21
  selectedNoteId,
6✔
22
  onNoteSelect,
6✔
23
  onNewNote,
6✔
24
  onDeleteNote,
6✔
25
  onRenameNote
6✔
26
}: LeftPanelProps) {
6✔
27
  const [filter, setFilter] = useState('');
6✔
28
  const [deleteDialog, setDeleteDialog] = useState<{
6✔
29
    isOpen: boolean;
30
    note: NoteTreeNode | null;
31
  }>({ isOpen: false, note: null });
6✔
32

33
  // Filter and prepare notes for TreeView
34
  const treeData = useMemo<NoteTreeNode[]>(() => {
6✔
35
    return notes
6✔
36
      .filter((note) => note.name.toLowerCase().includes(filter.toLowerCase()))
6✔
37
      .sort((a, b) => a.id - b.id);
6✔
38
  }, [notes, filter]);
6✔
39

40
  // Handle TreeNode selection
41
  const handleTreeNodeSelect = useCallback(
6✔
42
    (node: TreeNode) => {
6✔
43
      onNoteSelect((node as NoteTreeNode).id);
×
UNCOV
44
    },
×
45
    [onNoteSelect]
6✔
46
  );
6✔
47

48
  // Handle TreeNode rename
49
  const handleTreeNodeRename = useCallback(
6✔
50
    async (node: TreeNode, newName: string) => {
6✔
51
      await onRenameNote?.((node as NoteTreeNode).id, newName);
1✔
52
    },
1✔
53
    [onRenameNote]
6✔
54
  );
6✔
55

56
  // Handle TreeNode delete
57
  const handleTreeNodeDelete = useCallback((node: TreeNode) => {
6✔
58
    setDeleteDialog({ isOpen: true, note: node as NoteTreeNode });
×
59
  }, []);
6✔
60

61
  const handleConfirmDelete = useCallback(() => {
6✔
62
    if (deleteDialog.note) {
×
63
      onDeleteNote?.(deleteDialog.note.id);
×
UNCOV
64
    }
×
65
  }, [deleteDialog.note, onDeleteNote]);
6✔
66

67
  const handleCloseDeleteDialog = useCallback(() => {
6✔
UNCOV
68
    setDeleteDialog({ isOpen: false, note: null });
×
69
  }, []);
6✔
70

71
  return (
6✔
72
    <Box as="aside" h="100%" display="flex" flexDirection="column" p={6} bg="bg.subtle">
6✔
73
      <Stack gap={4} align="stretch">
6✔
74
        <Button colorPalette="blue" variant="solid" onClick={onNewNote}>
6✔
75
          New Note
76
        </Button>
6✔
77

78
        <Input
6✔
79
          p={3}
6✔
80
          placeholder="Filter notes..."
6✔
81
          value={filter}
6✔
82
          onChange={(e) => setFilter(e.target.value)}
6✔
83
          size="sm"
6✔
84
        />
6✔
85
      </Stack>
6✔
86

87
      <Box flex={1} mt={4} overflow="auto">
6✔
88
        {treeData.length === 0 ? (
6!
UNCOV
89
          <Text textAlign="center" color="fg.muted" fontSize="sm" mt={4}>
×
UNCOV
90
            {notes.length === 0 ? 'No notes yet' : 'No matching notes'}
×
UNCOV
91
          </Text>
×
92
        ) : (
93
          <TreeView
6✔
94
            data={treeData}
6✔
95
            onNodeSelect={handleTreeNodeSelect}
6✔
96
            onNodeRename={handleTreeNodeRename}
6✔
97
            onNodeDelete={handleTreeNodeDelete}
6✔
98
            generateName={(node) => `${node.data?.dirty ? '* ' : ''}${node.name}`}
6!
99
            selectedNodeId={selectedNoteId?.toString()}
6!
100
            title=""
6✔
101
          />
6✔
102
        )}
103
      </Box>
6✔
104

105
      <ConfirmationDialog
6✔
106
        isOpen={deleteDialog.isOpen}
6✔
107
        onClose={handleCloseDeleteDialog}
6✔
108
        onConfirm={handleConfirmDelete}
6✔
109
        title="Delete Note"
6✔
110
        message={`Are you sure you want to delete "${deleteDialog.note?.name}"? This action cannot be undone.`}
6!
111
        confirmText="Delete"
6✔
112
        cancelText="Cancel"
6✔
113
        variant="danger"
6✔
114
      />
6✔
115
    </Box>
6✔
116
  );
117
});
6✔
118

119
export default LeftPanel;
1✔
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