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

apowers313 / aiforge / 21570337701

01 Feb 2026 09:11PM UTC coverage: 81.026% (-2.9%) from 83.954%
21570337701

push

github

apowers313
test: increase coverage to 80%+

2049 of 2382 branches covered (86.02%)

Branch coverage included in aggregate %.

1849 of 2529 new or added lines in 25 files covered. (73.11%)

681 existing lines in 21 files now uncovered.

9861 of 12317 relevant lines covered (80.06%)

26.33 hits per line

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

26.09
/src/client/components/context-sidebar/tabs/ProjectNotesTab.tsx
1
/**
2
 * ProjectNotesTab - Markdown notes editor for project context sidebar
3
 */
4
import { useState, useEffect, useCallback } from 'react';
1✔
5
import { Stack, Text, Loader, Alert, Group } from '@mantine/core';
1✔
6
import { useDebouncedCallback } from '@mantine/hooks';
1✔
7
import MDEditor, { commands } from '@uiw/react-md-editor';
1✔
8
import { useProjectContext } from '@client/hooks/useProjectContext';
1✔
9

10
// Curated toolbar commands with logical grouping
11
const toolbarCommands = [
1✔
12
  // Text formatting
13
  commands.bold,
1✔
14
  commands.italic,
1✔
15
  commands.strikethrough,
1✔
16
  commands.group([commands.heading1, commands.heading2, commands.heading3], {
1✔
17
    name: 'heading',
1✔
18
    groupName: 'heading',
1✔
19
    buttonProps: { 'aria-label': 'Insert heading' },
1✔
20
  }),
1✔
21
  commands.divider,
1✔
22
  // Content elements
23
  commands.link,
1✔
24
  commands.quote,
1✔
25
  commands.code,
1✔
26
  commands.divider,
1✔
27
  // Lists
28
  commands.unorderedListCommand,
1✔
29
  commands.checkedListCommand,
1✔
30
];
1✔
31

32
// Extra commands (right side of toolbar)
33
const extraCommands = [commands.help];
1✔
34

35
interface ProjectNotesTabProps {
36
  projectId: string;
37
}
38

39
export function ProjectNotesTab({ projectId }: ProjectNotesTabProps): React.ReactElement {
1✔
NEW
40
  const { notes, isLoading, isError, error, updateNotes, isUpdatingNotes } = useProjectContext(projectId);
×
NEW
41
  const [draft, setDraft] = useState(notes);
×
NEW
42
  const [isSaving, setIsSaving] = useState(false);
×
43

44
  // Sync draft with server notes when they change
NEW
45
  useEffect(() => {
×
NEW
46
    setDraft(notes);
×
NEW
47
  }, [notes]);
×
48

49
  // Debounced save to server
NEW
50
  const debouncedSave = useDebouncedCallback(
×
NEW
51
    useCallback(
×
NEW
52
      async (content: string): Promise<void> => {
×
NEW
53
        setIsSaving(true);
×
NEW
54
        try {
×
NEW
55
          await updateNotes(content);
×
NEW
56
        } finally {
×
NEW
57
          setIsSaving(false);
×
NEW
58
        }
×
NEW
59
      },
×
NEW
60
      [updateNotes],
×
NEW
61
    ),
×
NEW
62
    500,
×
NEW
63
  );
×
64

NEW
65
  const handleChange = (value?: string): void => {
×
NEW
66
    const newValue = value ?? '';
×
NEW
67
    setDraft(newValue);
×
NEW
68
    debouncedSave(newValue);
×
NEW
69
  };
×
70

NEW
71
  if (isLoading) {
×
NEW
72
    return (
×
NEW
73
      <Stack align="center" justify="center" p="lg" data-testid="notes-loading">
×
NEW
74
        <Loader size="sm" />
×
NEW
75
        <Text size="sm" c="dimmed">
×
76
          Loading notes...
NEW
77
        </Text>
×
NEW
78
      </Stack>
×
79
    );
NEW
80
  }
×
81

NEW
82
  if (isError) {
×
NEW
83
    return (
×
NEW
84
      <Alert color="red" title="Error">
×
NEW
85
        {error?.message ?? 'Failed to load notes'}
×
NEW
86
      </Alert>
×
87
    );
NEW
88
  }
×
89

NEW
90
  return (
×
NEW
91
    <Stack gap="xs" h="100%">
×
NEW
92
      {(isSaving || isUpdatingNotes) && (
×
NEW
93
        <Group gap="xs" px="xs" data-testid="notes-saving">
×
NEW
94
          <Loader size="xs" />
×
NEW
95
          <Text size="xs" c="dimmed">
×
96
            Saving...
NEW
97
          </Text>
×
NEW
98
        </Group>
×
99
      )}
NEW
100
      <div data-testid="notes-editor" data-color-mode="dark" style={{ flex: 1, minHeight: 0 }}>
×
NEW
101
        <MDEditor
×
NEW
102
          value={draft}
×
NEW
103
          onChange={handleChange}
×
NEW
104
          preview="edit"
×
NEW
105
          height="100%"
×
NEW
106
          visibleDragbar={false}
×
NEW
107
          hideToolbar={false}
×
NEW
108
          commands={toolbarCommands}
×
NEW
109
          extraCommands={extraCommands}
×
NEW
110
          textareaProps={{
×
NEW
111
            placeholder: 'Add notes here...',
×
NEW
112
          }}
×
NEW
113
          style={{
×
NEW
114
            backgroundColor: 'transparent',
×
NEW
115
            minHeight: '200px',
×
NEW
116
          }}
×
NEW
117
        />
×
NEW
118
      </div>
×
NEW
119
    </Stack>
×
120
  );
NEW
121
}
×
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