Skip to content

Commit bf18946

Browse files
committed
Polish Project Workspace banner layout and active project state - PR_26155_050-052-project-workspace-polish
1 parent 366af98 commit bf18946

7 files changed

Lines changed: 158 additions & 21 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Admin Project Data Alignment
2+
3+
Stack item: PR_26155_050-admin-project-data-alignment
4+
5+
## Summary
6+
- Updated `toolbox/index.html` so the role simulation banner reuses the existing Theme V2 `section-head` row pattern.
7+
- Kept the admin banner text on the left and the `Project Data ▾` menu on the right side of the same banner row.
8+
- Project Data controls remain admin-only through the existing role simulation behavior.
9+
10+
## Validation Notes
11+
- Impacted lane: `project-workspace`.
12+
- PASS: `npm run test:lane:project-workspace`.
13+
- PASS: `git diff --check`.
14+
- Skipped lanes: `tool-runtime`, `workspace-contract`, `game-runtime`, `integration`, `engine-src`, `samples`, and full samples smoke.
15+
- Skipped-lane rationale: this PR only changes the Project Workspace/Toolbox banner and Project Workspace page layout behavior; it does not change engine runtime, games, samples, cross-tool launch behavior, or shared Theme V2 CSS.
16+
17+
## Manual Test Notes
18+
- Verified in targeted Playwright that `?role=admin` shows the admin banner and Project Data menu on the same row.
19+
- Verified Project Data remains hidden for `?role=guest` and `?role=user`.
20+
- Verified no new CSS was added; existing Theme V2 classes support the row alignment.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Project Workspace Open Project State
2+
3+
Stack item: PR_26155_052-project-workspace-open-project-state
4+
5+
## Summary
6+
- Removed the separate `Open` status label that appeared beside the active project row.
7+
- Highlighted the currently open project button with the existing Theme V2 `btn primary` classes.
8+
- Added `aria-current="true"` and `data-project-active="true"` to the active project button.
9+
- Updated button text to include `(Active)` for the currently open project.
10+
11+
## Validation Notes
12+
- Impacted lane: `project-workspace`.
13+
- PASS: `npm run test:lane:project-workspace`.
14+
- PASS: `git diff --check`.
15+
- No DB, auth, cloud, persistence, or new CSS behavior was added.
16+
17+
## Manual Test Notes
18+
- Verified `Open Demo Project` no longer has a separate `Open` label.
19+
- Verified the active/open project is indicated directly on the button.
20+
- Verified create, open, and delete project behavior still works.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Project Workspace Panel Layout Polish
2+
3+
Stack item: PR_26155_051-project-workspace-panel-layout-polish
4+
5+
## Summary
6+
- Moved `Readiness Output`, `Repository Tables`, and `Project Members` out of the right Inspector column.
7+
- Placed those three output accordions in the center panel between `Static Overlay Wireframe` and `Missing Requirements`.
8+
- Kept the left panel for setup/input, the center panel for primary project work and outputs, and the right panel for inspector status/logging.
9+
10+
## Validation Notes
11+
- Impacted lane: `project-workspace`.
12+
- PASS: `npm run test:lane:project-workspace`.
13+
- PASS: `node --check toolbox/project-workspace/project-workspace.js`.
14+
- PASS: `node --check tests/playwright/tools/ProjectWorkspaceMockRepository.spec.mjs`.
15+
- PASS: `git diff --check`.
16+
17+
## Manual Test Notes
18+
- Verified the center panel order is:
19+
- `Static Overlay Wireframe`
20+
- `Readiness Output`, `Repository Tables`, `Project Members`
21+
- `Missing Requirements`
22+
- Verified the right column no longer contains the moved output accordions.
23+
- Verified no console errors in the targeted Project Workspace lane.

tests/playwright/tools/ProjectWorkspaceMockRepository.spec.mjs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,16 @@ test("Project Workspace creates, opens, and deletes mock projects", async ({ pag
5454
await expect(page.locator("style, [style], script:not([src])")).toHaveCount(0);
5555
await expect(page.locator("[data-active-project-name]")).toHaveText("Demo Project");
5656
await expect(page.locator("[data-project-list]")).toContainText("Demo Project");
57+
const demoProjectRow = page.locator("[data-project-row='demo-project']");
58+
await expect(demoProjectRow.locator("> .status")).toHaveCount(0);
59+
await expect(demoProjectRow.getByRole("button", { name: "Open Demo Project (Active)" })).toHaveClass(/primary/);
60+
await expect(demoProjectRow.getByRole("button", { name: "Open Demo Project (Active)" })).toHaveAttribute("aria-current", "true");
5761

5862
await page.getByLabel("Project Name").fill("Launch Test Project");
5963
await page.getByRole("button", { name: "Create Project" }).click();
6064
await expect(page.locator("[data-active-project-name]")).toHaveText("Launch Test Project");
6165
await expect(page.locator("[data-project-list]")).toContainText("Launch Test Project");
66+
await expect(page.locator("[data-project-row='launch-test-project-1']").getByRole("button", { name: "Open Launch Test Project (Active)" })).toHaveClass(/primary/);
6267
await expect(page.locator("[data-project-workspace-log]")).toHaveText("Created and opened Launch Test Project.");
6368

6469
await page.getByLabel("Project Name").fill("Archive Project");
@@ -67,6 +72,7 @@ test("Project Workspace creates, opens, and deletes mock projects", async ({ pag
6772

6873
await page.getByRole("button", { name: "Open Launch Test Project" }).click();
6974
await expect(page.locator("[data-active-project-name]")).toHaveText("Launch Test Project");
75+
await expect(page.locator("[data-project-row='launch-test-project-1']").getByRole("button", { name: "Open Launch Test Project (Active)" })).toHaveAttribute("data-project-active", "true");
7076
await expect(page.locator("[data-project-workspace-log]")).toHaveText("Opened Launch Test Project.");
7177

7278
await page.getByRole("button", { name: "Delete Open Project" }).click();
@@ -90,6 +96,27 @@ test("Project Workspace progress panels update from mock project state", async (
9096
await expect(page.locator("[data-current-focus]")).toHaveText("Complete Game Configuration");
9197
await expect(page.locator("[data-recommended-next-tool]").first()).toHaveText("Game Configuration");
9298
await expect(page.locator("[data-project-progress-checklist]")).toContainText("Project identity: Complete");
99+
await expect(page.locator("[data-project-output-panels] summary")).toHaveText([
100+
"Readiness Output",
101+
"Repository Tables",
102+
"Project Members"
103+
]);
104+
await expect(page.locator("aside.tool-column").last().getByText("Readiness Output")).toHaveCount(0);
105+
await expect(page.locator("aside.tool-column").last().getByText("Repository Tables")).toHaveCount(0);
106+
await expect(page.locator("aside.tool-column").last().getByText("Project Members")).toHaveCount(0);
107+
const panelOrderIsCorrect = await page.locator(".tool-center-panel").evaluate((panel) => {
108+
const staticOverlay = panel.querySelector("[data-static-overlay-wireframe]");
109+
const outputPanels = panel.querySelector("[data-project-output-panels]");
110+
const missingRequirements = panel.querySelector("[data-missing-requirements]");
111+
return Boolean(
112+
staticOverlay &&
113+
outputPanels &&
114+
missingRequirements &&
115+
(staticOverlay.compareDocumentPosition(outputPanels) & Node.DOCUMENT_POSITION_FOLLOWING) &&
116+
(outputPanels.compareDocumentPosition(missingRequirements) & Node.DOCUMENT_POSITION_FOLLOWING)
117+
);
118+
});
119+
expect(panelOrderIsCorrect).toBe(true);
93120

94121
await page.getByLabel("Project Name").fill("Progress Review Project");
95122
await page.getByRole("button", { name: "Create Project" }).click();
@@ -125,6 +152,13 @@ test("Toolbox Project Data controls are admin-only and drive mock Progress and B
125152
await page.goto(`${failures.server.baseUrl}/toolbox/index.html?role=admin`, { waitUntil: "networkidle" });
126153
await expect(page.locator("[data-toolbox-role-banner]")).toHaveText(/ADMIN VIEW.*Planned tools visible.*Switch to Creator View/);
127154
await expect(page.locator("[data-project-data-menu]")).toBeVisible();
155+
await expect(page.locator("[aria-label='Toolbox role simulation']")).toHaveClass(/section-head/);
156+
const roleBannerBox = await page.locator("[data-toolbox-role-banner]").boundingBox();
157+
const projectDataBox = await page.locator("[data-project-data-menu] > summary").boundingBox();
158+
expect(roleBannerBox).not.toBeNull();
159+
expect(projectDataBox).not.toBeNull();
160+
expect(Math.abs((roleBannerBox.y + roleBannerBox.height / 2) - (projectDataBox.y + projectDataBox.height / 2))).toBeLessThan(16);
161+
expect(projectDataBox.x).toBeGreaterThan(roleBannerBox.x + roleBannerBox.width);
128162
await page.locator("[data-project-data-menu] summary").click();
129163

130164
await page.getByRole("button", { name: "Clear Test Data" }).click();

toolbox/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<body>
1414
<div data-partial="header-nav"></div>
15-
<div class="container callout" aria-label="Toolbox role simulation">
15+
<div class="container callout section-head" aria-label="Toolbox role simulation">
1616
<a class="status" href="toolbox/index.html?role=user" data-toolbox-role-banner>GUEST VIEW • Preview only • Sign in to create</a>
1717
<details class="status" data-project-data-menu hidden>
1818
<summary>Project Data ▾</summary>

toolbox/project-workspace/index.html

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ <h3 data-active-project-name>Demo Project</h3>
7474
</div>
7575
</div>
7676
</article>
77-
<article class="card">
77+
<article class="card" data-static-overlay-wireframe>
7878
<div class="card-body content-stack">
7979
<div>
80-
<div class="kicker">Progress Panels</div>
80+
<div class="kicker">Static Overlay Wireframe</div>
8181
<h3>Project Progress</h3>
8282
</div>
8383
<div class="grid cols-3">
@@ -93,12 +93,25 @@ <h3>Project Progress</h3>
9393
<div class="status" role="status" data-project-workspace-log>Mock repository seeded with Demo Project.</div>
9494
</div>
9595
</article>
96-
</section>
97-
<aside class="tool-column tool-group-development-system">
98-
<div class="tool-column-header forge-gold">
99-
<h2>Inspector</h2>
100-
</div>
101-
<div class="accordion-stack">
96+
<div class="accordion-stack" data-project-output-panels>
97+
<details class="vertical-accordion" open>
98+
<summary>Readiness Output</summary>
99+
<div class="accordion-body">
100+
<div class="table-wrapper">
101+
<table class="data-table">
102+
<caption>Mock readiness output</caption>
103+
<thead>
104+
<tr><th scope="col">Path</th><th scope="col">Status</th><th scope="col">Next Tool</th></tr>
105+
</thead>
106+
<tbody>
107+
<tr><td>Plan</td><td>Under Construction</td><td>Game Configuration</td></tr>
108+
<tr><td>Configure</td><td>Planned</td><td>Build Game</td></tr>
109+
<tr><td>Release</td><td>Planned</td><td>Publish</td></tr>
110+
</tbody>
111+
</table>
112+
</div>
113+
</div>
114+
</details>
102115
<details class="vertical-accordion" open>
103116
<summary>Repository Tables</summary>
104117
<div class="accordion-body">
@@ -134,6 +147,35 @@ <h2>Inspector</h2>
134147
</div>
135148
</details>
136149
</div>
150+
<article class="card" role="dialog" aria-labelledby="project-workspace-missing-requirements-title" data-missing-requirements>
151+
<div class="card-body content-stack">
152+
<div>
153+
<div class="kicker">Mock Requirements</div>
154+
<h3 id="project-workspace-missing-requirements-title">Missing Requirements</h3>
155+
</div>
156+
<p>This card remains a static review surface for the next required tools. It does not block, save, or validate runtime state.</p>
157+
<div class="grid cols-3">
158+
<article class="callout"><h3>Game Design</h3><p><span class="pill">Under Construction</span> Define win and lose conditions.</p></article>
159+
<article class="callout"><h3>Game Configuration</h3><p><span class="pill">Planned</span> Choose release profile and debug policy.</p></article>
160+
<article class="callout"><h3>Publish</h3><p><span class="pill">Planned</span> Prepare share metadata later.</p></article>
161+
</div>
162+
<div class="status" role="status">Mock-only: Project Workspace does not run real publish gating yet.</div>
163+
</div>
164+
</article>
165+
</section>
166+
<aside class="tool-column tool-group-development-system">
167+
<div class="tool-column-header forge-gold">
168+
<h2>Inspector</h2>
169+
</div>
170+
<div class="accordion-stack">
171+
<details class="vertical-accordion" open>
172+
<summary>Status Log</summary>
173+
<div class="accordion-body">
174+
<p>Project Workspace operations report status in the center panel while the right column stays reserved for inspector status and diagnostics.</p>
175+
<div class="status" role="status">Mock repository ready.</div>
176+
</div>
177+
</details>
178+
</div>
137179
</aside>
138180
</div>
139181
</div>

toolbox/project-workspace/project-workspace.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,16 @@ function setStatusLog(message) {
4141
setText(elements.statusLog, message);
4242
}
4343

44-
function createProjectButton(project) {
44+
function createProjectButton(project, isActive) {
4545
const button = document.createElement("button");
46-
button.className = "btn";
46+
button.className = isActive ? "btn primary" : "btn";
4747
button.type = "button";
4848
button.dataset.projectOpen = project.id;
49-
button.textContent = `Open ${project.name}`;
49+
if (isActive) {
50+
button.dataset.projectActive = "true";
51+
button.setAttribute("aria-current", "true");
52+
}
53+
button.textContent = isActive ? `Open ${project.name} (Active)` : `Open ${project.name}`;
5054
return button;
5155
}
5256

@@ -80,16 +84,10 @@ function renderProjectList() {
8084
meta.className = "eyebrow";
8185
meta.textContent = `${project.status} | ${project.ownerDisplayName}`;
8286

83-
const action = createProjectButton(project);
87+
const isActive = activeProject?.id === project.id;
88+
const action = createProjectButton(project, isActive);
8489

85-
if (activeProject?.id === project.id) {
86-
const active = document.createElement("span");
87-
active.className = "status";
88-
active.textContent = "Open";
89-
row.append(title, meta, active, action);
90-
} else {
91-
row.append(title, meta, action);
92-
}
90+
row.append(title, meta, action);
9391

9492
elements.projectList.append(row);
9593
});

0 commit comments

Comments
 (0)