Skip to content

Commit 4b669f2

Browse files
committed
Consolidate MIDI Studio V2 accordions into existing tab-specific buckets - PR_26146_054-midi-studio-v2-existing-tab-bucket-consolidation
1 parent 25112e4 commit 4b669f2

4 files changed

Lines changed: 235 additions & 12 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# PR_26146_054 MIDI Studio V2 Existing Tab Bucket Consolidation Validation
2+
3+
## Summary
4+
5+
Status: PASS
6+
7+
Playwright impacted: Yes
8+
9+
This PR consolidates MIDI Studio V2 accordions/data into the six existing tabs without adding new tabs. Shared buckets were narrowed to their most specific owner tab while preserving the canonical song model and canvas-backed Octave Timeline.
10+
11+
## Files Changed
12+
13+
- `tools/midi-studio-v2/index.html`
14+
- `tests/playwright/tools/MidiStudioV2.spec.mjs`
15+
- `docs/dev/reports/PR_26146_054-midi-studio-v2-existing-tab-bucket-consolidation_validation.md`
16+
- `docs/dev/reports/PR_26146_054-midi-studio-v2-tab-bucket-map.md`
17+
- `docs/dev/codex_commands.md`
18+
- `docs/dev/commit_comment.txt`
19+
20+
## Validation Commands
21+
22+
- PASS: `node --check tests/playwright/tools/MidiStudioV2.spec.mjs`
23+
- PASS: HTML external-only check for `<script>` usage.
24+
- PASS: HTML no-inline-style/no-inline-handler check for `<style| on[a-z]+=`.
25+
- PASS: `npx playwright test tests/playwright/tools/MidiStudioV2.spec.mjs --grep "consolidates existing tab buckets|canvas octave timeline edits canonical data"`.
26+
- PASS: `git diff --check` with line-ending warnings only.
27+
28+
## Playwright Coverage
29+
30+
The targeted MIDI Studio V2 tests prove:
31+
32+
- No new tabs were added.
33+
- Song Setup, Octave Timeline, Instruments, Auto-Create Parts, MIDI Import, and Diagnostics all still exist.
34+
- Songs, Song Details, Song Sheet, and Sections / Loop are visible only on Song Setup.
35+
- Instrument rows, GM Type, GM Instrument/Patch, add/delete, visibility, mute, and solo controls are visible only on Instruments.
36+
- MIDI import path/source, instrument set, import, inspect, and status details are visible only on MIDI Import.
37+
- Diagnostics accordions are visible only on Diagnostics.
38+
- Diagnostics has no non-read-only form controls except diagnostic actions such as Copy JSON and Clear.
39+
- Editable Song Setup fields still update the canonical model from their owning tab.
40+
- Octave Timeline still renders and edits canvas note data.
41+
- Play and Stop still work.
42+
43+
## Coverage Artifacts
44+
45+
- `docs/dev/reports/playwright_v8_coverage_report.txt` was refreshed by the targeted Playwright run.
46+
- `docs/dev/reports/coverage_changed_js_guardrail.txt` was refreshed by the targeted Playwright run.
47+
- Changed runtime JS coverage guardrail reports no warnings.
48+
49+
## Samples Decision
50+
51+
Full samples smoke test: SKIP.
52+
53+
Reason: explicitly out of scope for this PR and not requested; this change is limited to MIDI Studio V2 tab/bucket ownership.
54+
55+
## Manual Validation Notes
56+
57+
1. Open MIDI Studio V2 and import the UAT manifest.
58+
2. Verify the tab row contains only Song Setup, Octave Timeline, Instruments, Auto-Create Parts, MIDI Import, and Diagnostics.
59+
3. Switch through each tab and confirm each bucket appears only under its owning tab.
60+
4. Edit Song Setup fields and confirm the selected song model updates.
61+
5. Open Octave Timeline, edit a note, then Play and Stop.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# PR_26146_054 MIDI Studio V2 Tab Bucket Map
2+
3+
## Tab Order
4+
5+
1. Song Setup
6+
2. Octave Timeline
7+
3. Instruments
8+
4. Auto-Create Parts
9+
5. MIDI Import
10+
6. Diagnostics
11+
12+
## Song Setup
13+
14+
- Songs list: `songListContent`
15+
- Song Details: `songDetailsContent`
16+
- Name
17+
- Id
18+
- Tempo/BPM
19+
- Key
20+
- Style
21+
- Tags
22+
- Usage
23+
- Notes
24+
- Song Sheet: `songSheetContent`
25+
- Intro/Loop chord progression
26+
- Parse action
27+
- Song Sheet status and summary
28+
- Sections / Loop: `songSectionsLoopContent`
29+
- Section labels
30+
- Loop enabled/start/end song-level setup fields
31+
32+
## Octave Timeline
33+
34+
- Canvas/grid editing surface: `instrumentGridOutput`
35+
- Timeline zoom controls and title
36+
- Grid-owned playback controls: `transportContent`
37+
- Loop playback toggle: `loopToggle`
38+
- Selected timeline/note context: `timelineSelectionContent`
39+
40+
## Instruments
41+
42+
- Instrument rows and management: `instrumentListContent`
43+
- GM Type dropdowns
44+
- GM Instrument/Patch dropdowns
45+
- Add instrument
46+
- Delete instrument
47+
- Visibility, mute, solo, volume, and pan controls
48+
49+
## Auto-Create Parts
50+
51+
- Helper-only grid controls:
52+
- `instrumentGridSectionsInput`
53+
- `instrumentGridBeatsInput`
54+
- `instrumentGridSubdivisionInput`
55+
- `instrumentGridLaneTypeSelect`
56+
- Advanced lane source text
57+
- Generate Bass From Chords
58+
- Generate Pad From Chords
59+
- Generate Arpeggio From Chords
60+
- Generate Basic Drums
61+
- Normalize Grid
62+
63+
## MIDI Import
64+
65+
- MIDI source path/file picker: `songSourceField`, `midiFileInput`
66+
- Import inspection instrument set: `instrumentSetField`
67+
- Import MIDI Source
68+
- Inspect MIDI Source
69+
- MIDI import status/details: `midiSourceDetails`
70+
71+
## Diagnostics
72+
73+
- JSON Details: `inspectorContent`
74+
- Timeline Diagnostics: `instrumentGridSummaryContent`
75+
- Audio Diagnostics: `audioDiagnosticsContent`
76+
- Rendered Preview diagnostics: `playbackContent`
77+
- Rendered Export Targets diagnostics: `renderedTargetsContent`
78+
- Game Music Director derived/debug metadata: `directorContent`
79+
- Status/log output: `statusLogContent`
80+
- Diagnostic actions:
81+
- Copy JSON
82+
- Clear status

tests/playwright/tools/MidiStudioV2.spec.mjs

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,7 +1886,7 @@ test.describe("MIDI Studio V2", () => {
18861886
}
18871887
});
18881888

1889-
test("restores Song Setup editable buckets without duplicating diagnostics", async ({ page }) => {
1889+
test("consolidates existing tab buckets without duplicate editable fields", async ({ page }) => {
18901890
const server = await openMidiStudioForImport(page);
18911891
try {
18921892
await page.locator("#toolImportManifestInput").setInputFiles(uatManifestPath);
@@ -1898,13 +1898,21 @@ test.describe("MIDI Studio V2", () => {
18981898
{ id: "song-setup", text: "Song Setup" },
18991899
{ id: "studio", text: "Octave Timeline" }
19001900
]);
1901+
expect(tabs).toHaveLength(6);
1902+
expect(tabs.map((tab) => tab.text)).toEqual([
1903+
"Song Setup",
1904+
"Octave Timeline",
1905+
"Instruments",
1906+
"Auto-Create Parts",
1907+
"MIDI Import",
1908+
"Diagnostics"
1909+
]);
19011910
expect(tabs.map((tab) => tab.text)).not.toContain("Studio");
19021911
await expect(page.locator('[data-midi-studio-tab="song-setup"]')).toHaveAttribute("aria-selected", "true");
19031912
await expect(page.locator('.accordion-v2__header[aria-controls="songListContent"]')).toContainText("Songs");
19041913
await expect(page.locator('.accordion-v2__header[aria-controls="songDetailsContent"]')).toContainText("Song Details");
19051914
await expect(page.locator('.accordion-v2__header[aria-controls="songSheetContent"]')).toContainText("Song Sheet");
19061915
await expect(page.locator('.accordion-v2__header[aria-controls="songSectionsLoopContent"]')).toContainText("Sections / Loop");
1907-
await expect(page.locator('.accordion-v2__header[aria-controls="statusLogContent"]')).toContainText("Status");
19081916
await expect(page.locator("#songDetailsContent")).toBeVisible();
19091917
await expect(page.locator("#songSheetContent")).toBeVisible();
19101918
await expect(page.locator("#songSectionsLoopContent")).toBeVisible();
@@ -1932,6 +1940,8 @@ test.describe("MIDI Studio V2", () => {
19321940
await expect(page.locator("#audioDiagnosticsContent")).toBeHidden();
19331941
await expect(page.locator("#instrumentGridSummaryContent")).toBeHidden();
19341942
await expect(page.locator("#midiImportContent")).toBeHidden();
1943+
await expect(page.locator("#instrumentListContent")).toBeHidden();
1944+
await expect(page.locator("#statusLogContent")).toBeHidden();
19351945
await expect(page.locator("#songDetailsContent #midiImportContent")).toHaveCount(0);
19361946
await expect(page.locator("#songDetails [data-song-detail-field='sourceMidi']")).toHaveCount(0);
19371947
await expect(page.locator("#songDetails [data-song-detail-field='instrumentSet']")).toHaveCount(0);
@@ -1981,10 +1991,80 @@ test.describe("MIDI Studio V2", () => {
19811991
await expect(page.locator("#songDetails [data-song-detail-field='usage']")).toHaveValue("uat, frog-hop, nursery-rhyme");
19821992

19831993
await selectMidiStudioTab(page, "instruments");
1994+
await expect(page.locator("#instrumentListContent")).toBeVisible();
1995+
await expect(instrumentTypeSelect(page, "lead")).toBeVisible();
1996+
await expect(instrumentSelect(page, "lead")).toBeVisible();
1997+
await expect(page.locator("#addInstrumentRowButton")).toBeVisible();
1998+
await expect(instrumentToggle(page, "lead", "mute")).toBeVisible();
1999+
await expect(instrumentToggle(page, "lead", "solo")).toBeVisible();
2000+
await expect(instrumentRow(page, "lead").locator("[data-toggle-instrument-visibility='lead']")).toBeVisible();
2001+
await expect(instrumentRow(page, "lead").locator("[data-delete-instrument-row='lead']")).toBeVisible();
2002+
await expect(page.locator("#songListContent")).toBeHidden();
2003+
await expect(page.locator("#songDetailsContent")).toBeHidden();
2004+
await expect(page.locator("#songSheetContent")).toBeHidden();
2005+
await expect(page.locator("#midiImportContent")).toBeHidden();
2006+
await expect(page.locator("#instrumentGridOutput")).toBeHidden();
2007+
await expect(page.locator("#timelineSelectionContent")).toBeHidden();
2008+
await expect(page.locator("#audioDiagnosticsContent")).toBeHidden();
19842009
await selectInstrumentRow(page, "lead");
2010+
2011+
await selectMidiStudioTab(page, "auto-create-parts");
2012+
await expect(page.locator("#generateBassFromChordsButton")).toBeVisible();
2013+
await expect(page.locator("#generatePadFromChordsButton")).toBeVisible();
2014+
await expect(page.locator("#generateArpeggioFromChordsButton")).toBeVisible();
2015+
await expect(page.locator("#generateBasicDrumsButton")).toBeVisible();
2016+
await expect(page.locator("#normalizeInstrumentGridButton")).toBeVisible();
2017+
await expect(page.locator("#instrumentGridSectionsInput")).toBeVisible();
2018+
await expect(page.locator("#instrumentGridOutput")).toBeHidden();
2019+
await expect(page.locator("#loopToggle")).toBeHidden();
2020+
await expect(page.locator("#songDetailsContent")).toBeHidden();
2021+
await expect(page.locator("#instrumentListContent")).toBeHidden();
2022+
await expect(page.locator("#midiImportContent")).toBeHidden();
2023+
2024+
await selectMidiStudioTab(page, "midi-import");
2025+
await expect(page.locator("#midiImportContent")).toBeVisible();
2026+
await expect(page.locator("#songSourceField")).toBeVisible();
2027+
await expect(page.locator("#instrumentSetField")).toBeVisible();
2028+
await expect(page.locator("#importMidiSourceButton")).toBeVisible();
2029+
await expect(page.locator("#inspectMidiSourceButton")).toBeVisible();
2030+
await expect(page.locator("#midiSourceDetails")).toBeVisible();
2031+
await expect(page.locator("#songListContent")).toBeHidden();
2032+
await expect(page.locator("#songDetailsContent")).toBeHidden();
2033+
await expect(page.locator("#songSheetContent")).toBeHidden();
2034+
await expect(page.locator("#instrumentListContent")).toBeHidden();
2035+
await expect(page.locator("#audioDiagnosticsContent")).toBeHidden();
2036+
2037+
await selectMidiStudioTab(page, "diagnostics");
2038+
await expect(page.locator("#inspectorContent")).toBeVisible();
2039+
await expect(page.locator("#instrumentGridSummaryContent")).toBeVisible();
2040+
await expect(page.locator("#audioDiagnosticsContent")).toBeVisible();
2041+
await expect(page.locator("#playbackContent")).toBeVisible();
2042+
await expect(page.locator("#renderedTargetsContent")).toBeVisible();
2043+
await expect(page.locator("#directorContent")).toBeVisible();
2044+
await expect(page.locator("#statusLogContent")).toBeVisible();
2045+
await expect(page.locator("#songListContent")).toBeHidden();
2046+
await expect(page.locator("#songDetailsContent")).toBeHidden();
2047+
await expect(page.locator("#songSheetContent")).toBeHidden();
2048+
await expect(page.locator("#midiImportContent")).toBeHidden();
2049+
await expect(page.locator("#instrumentListContent")).toBeHidden();
2050+
await expect(page.locator("#loopToggle")).toBeHidden();
2051+
const diagnosticEditableControls = await page.locator('[data-midi-studio-tab-panel="diagnostics"] input:not([type="hidden"]), [data-midi-studio-tab-panel="diagnostics"] select, [data-midi-studio-tab-panel="diagnostics"] textarea:not([readonly])').count();
2052+
expect(diagnosticEditableControls).toBe(0);
2053+
await expect(page.locator("#toolCopyJsonButton")).toBeVisible();
2054+
await expect(page.locator("#clearStatusButton")).toBeVisible();
2055+
19852056
await selectMidiStudioTab(page, "studio");
19862057
await waitForCanvasRender(page);
19872058
await expect(octaveTimelineCanvas(page)).toBeVisible();
2059+
await expect(page.locator("#instrumentGridOutput")).toBeVisible();
2060+
await expect(page.locator("#timelineSelectionContent")).toBeVisible();
2061+
await expect(page.locator("#loopToggle")).toBeVisible();
2062+
await expect(page.locator("#songListContent")).toBeHidden();
2063+
await expect(page.locator("#songDetailsContent")).toBeHidden();
2064+
await expect(page.locator("#songSheetContent")).toBeHidden();
2065+
await expect(page.locator("#instrumentListContent")).toBeHidden();
2066+
await expect(page.locator("#midiImportContent")).toBeHidden();
2067+
await expect(page.locator("#instrumentGridSummaryContent")).toBeHidden();
19882068
await clickCanvasCell(page, "C6", 2);
19892069
expect(await page.evaluate(() => window.__midiStudioV2App.selectedSong().studioArrangement.lanes.lead)).toContain("C6");
19902070
await page.locator("#playButton").click();

tools/midi-studio-v2/index.html

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ <h2 class="tools-platform-frame__eyebrow">First-Class Tools Surface V2</h2>
8080

8181
<main class="tool-starter midi-studio-v2 app-shell tool-shell-common__fullscreen-root tool-shell-common__fullscreen-layout" data-tool-id="midi-studio-v2">
8282
<aside class="tool-starter__panel tool-starter__panel--left tool-shell-common__fullscreen-panel tool-shell-common__fullscreen-side-panel tool-shell-common__fullscreen-panel-left" aria-label="MIDI song setup">
83-
<section class="accordion-v2 tool-starter__accordion is-open" data-accordion-v2-open="true" data-midi-studio-tab-panel="studio song-setup midi-import">
83+
<section class="accordion-v2 tool-starter__accordion is-open" data-accordion-v2-open="true" data-midi-studio-tab-panel="song-setup">
8484
<button class="accordion-v2__header" type="button" aria-expanded="true" aria-controls="songListContent">
8585
<span>Songs</span>
8686
<span class="accordion-v2__icon" aria-hidden="true">+</span>
@@ -134,12 +134,6 @@ <h2 class="tools-platform-frame__eyebrow">First-Class Tools Surface V2</h2>
134134
<span class="accordion-v2__icon" aria-hidden="true">+</span>
135135
</button>
136136
<div id="playbackContent" class="accordion-v2__content">
137-
<div class="midi-studio-v2__playback-controls">
138-
<label class="tool-starter__toggle" for="loopToggle">
139-
<input id="loopToggle" type="checkbox">
140-
<span>Loop</span>
141-
</label>
142-
</div>
143137
<p id="playbackState" class="tool-starter__hint">No song selected.</p>
144138
</div>
145139
</section>
@@ -296,7 +290,13 @@ <h2 id="instrumentGridHeading">Octave Timeline</h2>
296290
<button id="generateBasicDrumsButton" type="button">Generate Basic Drums</button>
297291
<button id="normalizeInstrumentGridButton" type="button">Normalize Grid</button>
298292
</div>
299-
<div class="midi-studio-v2__transport-panel" aria-label="Instrument grid Preview Synth and timing preview" data-midi-studio-tab-panel="studio auto-create-parts">
293+
<div class="midi-studio-v2__transport-panel" aria-label="Instrument grid Preview Synth and timing preview" data-midi-studio-tab-panel="studio">
294+
<div class="midi-studio-v2__playback-controls">
295+
<label class="tool-starter__toggle" for="loopToggle">
296+
<input id="loopToggle" type="checkbox">
297+
<span>Loop</span>
298+
</label>
299+
</div>
300300
<div class="midi-studio-v2__section-presets" aria-label="Section shortcuts">
301301
<button class="midi-studio-v2__section-preset" type="button" data-section-preset="intro">Intro</button>
302302
<button class="midi-studio-v2__section-preset" type="button" data-section-preset="loop">Loop</button>
@@ -332,7 +332,7 @@ <h2 id="instrumentGridHeading">Octave Timeline</h2>
332332
</section>
333333

334334
<aside class="tool-starter__panel tool-starter__panel--right tool-shell-common__fullscreen-panel tool-shell-common__fullscreen-side-panel tool-shell-common__fullscreen-panel-right" aria-label="MIDI output">
335-
<section class="accordion-v2 tool-starter__accordion is-open" data-accordion-v2-open="true" data-midi-studio-tab-panel="studio instruments">
335+
<section class="accordion-v2 tool-starter__accordion is-open" data-accordion-v2-open="true" data-midi-studio-tab-panel="studio">
336336
<button class="accordion-v2__header" type="button" aria-expanded="true" aria-controls="timelineSelectionContent">
337337
<span>Selection</span>
338338
<span class="accordion-v2__icon" aria-hidden="true">+</span>
@@ -395,7 +395,7 @@ <h2 id="instrumentGridHeading">Octave Timeline</h2>
395395
</div>
396396
</section>
397397

398-
<section class="accordion-v2 tool-starter__accordion is-open" data-accordion-v2-open="true" data-midi-studio-tab-panel="studio song-setup diagnostics">
398+
<section class="accordion-v2 tool-starter__accordion is-open" data-accordion-v2-open="true" data-midi-studio-tab-panel="diagnostics">
399399
<div class="accordion-v2__header tool-starter__status-accordion-header" aria-expanded="true" aria-controls="statusLogContent">
400400
<span>Status</span>
401401
<div class="tool-starter__status-header-actions">

0 commit comments

Comments
 (0)