Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions apps/desktop/src/features/chords/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ const mockSong: RehearsalSong = {
range: { lowestNote: "D4", highestNote: "D5" },
confidence: { level: "high", reason: "test" },
rehearsalPriority: "high",
simplification: "none",
setupNote: "none",
simplification: "Simplify strumming pattern",
setupNote: "Drop D tuning",
manualOverrides: [],
overlapWarnings: [],
overlapWarnings: ["Density warning: competing with Bass"],
transpositionPlan: "Capo 2nd fret",
},
],
Expand Down Expand Up @@ -74,4 +74,22 @@ describe("ChordsFeature", () => {
expect(screen.getByText(/Capo 2nd fret/)).toBeInTheDocument();
expect(screen.getByText(/Transpose:/)).toBeInTheDocument();
});

it("renders setupNote when provided", () => {
render(<ChordsFeature title="Chords" song={mockSong} />);
expect(screen.getByText(/Drop D tuning/)).toBeInTheDocument();
expect(screen.getAllByText(/Setup:/).length).toBeGreaterThan(0);
});

it("renders simplification when provided", () => {
render(<ChordsFeature title="Chords" song={mockSong} />);
expect(screen.getByText(/Simplify strumming pattern/)).toBeInTheDocument();
expect(screen.getAllByText(/Simplification:/).length).toBeGreaterThan(0);
});

it("renders overlapWarnings when provided", () => {
render(<ChordsFeature title="Chords" song={mockSong} />);
expect(screen.getByText(/Density warning: competing with Bass/)).toBeInTheDocument();
expect(screen.getByText(/Overlap Warning:/)).toBeInTheDocument();
});
});
45 changes: 43 additions & 2 deletions apps/desktop/src/features/chords/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,37 @@ export function ChordsFeature(props: { title: string; song?: RehearsalSong | nul
}

// Collect unique chords across all sections and roles
const chordsBySectionLabel = new Map<string, { chord: string; functionLabel: string; source: string; roleName: string; transpositionPlan?: string }[]>();
const chordsBySectionLabel = new Map<string, {
chord: string;
functionLabel: string;
source: string;
roleName: string;
transpositionPlan?: string;
setupNote: string;
simplification: string;
overlapWarnings: string[];
}[]>();
for (const section of song.sections) {
const entries: { chord: string; functionLabel: string; source: string; roleName: string; transpositionPlan?: string }[] = [];
const entries: {
chord: string;
functionLabel: string;
source: string;
roleName: string;
transpositionPlan?: string;
setupNote: string;
simplification: string;
overlapWarnings: string[];
}[] = [];
for (const role of section.roles) {
entries.push({
chord: role.harmony.chord,
functionLabel: role.harmony.functionLabel,
source: role.harmony.source,
roleName: role.name,
transpositionPlan: role.transpositionPlan,
setupNote: role.setupNote,
simplification: role.simplification,
overlapWarnings: role.overlapWarnings,
});
}
chordsBySectionLabel.set(section.label, entries);
Expand Down Expand Up @@ -75,6 +96,26 @@ export function ChordsFeature(props: { title: string; song?: RehearsalSong | nul
<strong>Transpose:</strong> {role.transpositionPlan}
</div>
)}
{role.setupNote && (
<div style={{ marginTop: "6px", fontSize: "0.8em", color: "#08979c", backgroundColor: "#e6fffb", padding: "4px", borderRadius: "2px" }}>
<strong>Setup:</strong> {role.setupNote}
</div>
)}
{role.simplification && (
<div style={{ marginTop: "6px", fontSize: "0.8em", color: "#531dab", backgroundColor: "#f9f0ff", padding: "4px", borderRadius: "2px" }}>
<strong>Simplification:</strong> {role.simplification}
</div>
)}
Comment on lines +99 to +108

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

"none" 값을 역할 안내로 표시하지 마십시오.

Line 99와 Line 104의 조건은 비어 있지 않은 모든 문자열을 표시합니다. 테스트 fixture의 role-1setupNotesimplification"none"을 사용하므로, 현재 UI는 안내가 없는 역할에도 두 개의 정보 카드를 표시합니다.

"none"과 공백 문자열을 제외한 경우에만 카드를 렌더링하십시오. "none"이 화면에 없음을 검증하는 테스트도 추가하십시오.

수정 예시
+  const hasRoleDetail = (value: string) => {
+    const normalizedValue = value.trim();
+    return normalizedValue !== "" && normalizedValue.toLowerCase() !== "none";
+  };
+
-                {role.setupNote && (
+                {hasRoleDetail(role.setupNote) && (
                   <div style={{ marginTop: "6px", fontSize: "0.8em", color: "`#08979c`", backgroundColor: "`#e6fffb`", padding: "4px", borderRadius: "2px" }}>
                     <strong>Setup:</strong> {role.setupNote}
                   </div>
                 )}
-                {role.simplification && (
+                {hasRoleDetail(role.simplification) && (
                   <div style={{ marginTop: "6px", fontSize: "0.8em", color: "`#531dab`", backgroundColor: "`#f9f0ff`", padding: "4px", borderRadius: "2px" }}>
                     <strong>Simplification:</strong> {role.simplification}
                   </div>
                 )}
📝 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
{role.setupNote && (
<div style={{ marginTop: "6px", fontSize: "0.8em", color: "#08979c", backgroundColor: "#e6fffb", padding: "4px", borderRadius: "2px" }}>
<strong>Setup:</strong> {role.setupNote}
</div>
)}
{role.simplification && (
<div style={{ marginTop: "6px", fontSize: "0.8em", color: "#531dab", backgroundColor: "#f9f0ff", padding: "4px", borderRadius: "2px" }}>
<strong>Simplification:</strong> {role.simplification}
</div>
)}
const hasRoleDetail = (value: string) => {
const normalizedValue = value.trim();
return normalizedValue !== "" && normalizedValue.toLowerCase() !== "none";
};
{hasRoleDetail(role.setupNote) && (
<div style={{ marginTop: "6px", fontSize: "0.8em", color: "`#08979c`", backgroundColor: "`#e6fffb`", padding: "4px", borderRadius: "2px" }}>
<strong>Setup:</strong> {role.setupNote}
</div>
)}
{hasRoleDetail(role.simplification) && (
<div style={{ marginTop: "6px", fontSize: "0.8em", color: "`#531dab`", backgroundColor: "`#f9f0ff`", padding: "4px", borderRadius: "2px" }}>
<strong>Simplification:</strong> {role.simplification}
</div>
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/features/chords/index.tsx` around lines 99 - 108, Update the
conditional rendering for role.setupNote and role.simplification in the chord
role UI to skip cards when the value is "none" or whitespace-only, while
preserving display for meaningful text. Add or update a test covering fixture
role-1 to verify that neither "Setup" nor "Simplification" card is rendered for
these values.

{role.overlapWarnings && role.overlapWarnings.length > 0 && (
<div style={{ marginTop: "6px", fontSize: "0.8em", color: "#cf1322", backgroundColor: "#fff1f0", padding: "4px", borderRadius: "2px" }}>
<strong>Overlap Warning:</strong>
<ul style={{ margin: "2px 0 0 16px", padding: 0 }}>
{role.overlapWarnings.map((warning, idx) => (
<li key={idx}>{warning}</li>
))}
</ul>
</div>
)}
</div>
))}
</div>
Expand Down
32 changes: 3 additions & 29 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading