Skip to content

Commit 72dd0f3

Browse files
committed
Fix Toolbox filters and add Color Picker Preview controls - PR_26160_059-toolbox-filters-and-color-picker-controls
1 parent 4090ff3 commit 72dd0f3

7 files changed

Lines changed: 294 additions & 68 deletions

File tree

assets/theme-v2/css/accordion.css

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,30 @@ details.vertical-accordion summary .action-group--end {
139139
margin-left: auto
140140
}
141141

142+
.accordion-summary-controls {
143+
flex: 0 1 auto;
144+
flex-wrap: nowrap;
145+
justify-content: flex-end;
146+
margin-left: auto;
147+
min-width: var(--space-0);
148+
overflow-x: auto
149+
}
150+
151+
.accordion-summary-controls .field-inline {
152+
flex: 0 0 auto;
153+
gap: var(--space-6)
154+
}
155+
156+
.accordion-summary-controls input[type="range"] {
157+
flex: 0 0 var(--space-78);
158+
width: var(--space-78);
159+
min-width: var(--space-44)
160+
}
161+
162+
.accordion-summary-controls .slider-current-value {
163+
min-width: var(--space-34)
164+
}
165+
142166
details.vertical-accordion[open] summary:active:after {
143167
background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%)
144168
}

docs_build/dev/reports/coverage_changed_js_guardrail.txt

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,9 @@ Missing changed runtime JS files are WARN, not FAIL.
66
Source: Playwright/Chromium built-in V8 coverage from the active Playwright run.
77

88
Changed runtime JS files considered:
9-
(0%) admin/tool-votes.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
10-
(0%) src/dev-runtime/guest-seeds/tool-state-samples.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
11-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
12-
(0%) src/dev-runtime/server/mock-api-router.mjs - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
13-
(50%) src/engine/api/toolbox-votes-api-client.js - executed lines 28/28; executed functions 2/4
14-
(85%) toolbox/tools-page-accordions.js - executed lines 1033/1033; executed functions 93/109
9+
(0%) toolbox/colors/colors.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
10+
(0%) toolbox/tools-page-accordions.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
1511

1612
Guardrail warnings:
17-
(0%) admin/tool-votes.js - WARNING: changed runtime JS file missing from coverage; advisory only
18-
(0%) src/dev-runtime/guest-seeds/tool-state-samples.js - WARNING: changed runtime JS file missing from coverage; advisory only
19-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: changed runtime JS file missing from coverage; advisory only
20-
(0%) src/dev-runtime/server/mock-api-router.mjs - WARNING: changed runtime JS file missing from coverage; advisory only
13+
(0%) toolbox/colors/colors.js - WARNING: changed runtime JS file missing from coverage; advisory only
14+
(0%) toolbox/tools-page-accordions.js - WARNING: changed runtime JS file missing from coverage; advisory only

docs_build/dev/reports/playwright_v8_coverage_report.txt

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,22 @@ Note: entry percentages use function coverage when available, otherwise line cov
1212
Note: coverage entries are aggregated across every page/tool where coverageReporter.start(page) and coverageReporter.stop(page) ran.
1313

1414
Exercised tool entry points detected:
15-
(79%) Toolbox Index - exercised 3 runtime JS files
15+
(0%) Toolbox Index - not exercised by this Playwright run
1616
(0%) Tool Template V2 - not exercised by this Playwright run
17-
(65%) Theme V2 Shared JS - exercised 1 runtime JS files
17+
(0%) Theme V2 Shared JS - not exercised by this Playwright run
1818

1919
Changed runtime JS files covered:
20-
(0%) admin/tool-votes.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
21-
(0%) src/dev-runtime/guest-seeds/tool-state-samples.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
22-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
23-
(0%) src/dev-runtime/server/mock-api-router.mjs - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
24-
(50%) src/engine/api/toolbox-votes-api-client.js - executed lines 28/28; executed functions 2/4
25-
(85%) toolbox/tools-page-accordions.js - executed lines 1033/1033; executed functions 93/109
20+
(0%) toolbox/colors/colors.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
21+
(0%) toolbox/tools-page-accordions.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
2622

2723
Files with executed line/function counts where available:
28-
(38%) src/engine/api/session-api-client.js - executed lines 34/34; executed functions 3/8
29-
(43%) toolbox/tool-registry-api-client.js - executed lines 148/148; executed functions 9/21
30-
(50%) src/engine/api/toolbox-votes-api-client.js - executed lines 28/28; executed functions 2/4
31-
(53%) src/engine/api/server-api-client.js - executed lines 159/159; executed functions 10/19
32-
(65%) assets/theme-v2/js/gamefoundry-partials.js - executed lines 547/547; executed functions 30/46
33-
(85%) toolbox/tools-page-accordions.js - executed lines 1033/1033; executed functions 93/109
34-
(100%) toolbox/project-workspace/project-workspace-api-client.js - executed lines 12/12; executed functions 2/2
24+
(100%) none - no covered runtime files
3525

3626
Uncovered or low-coverage changed JS files:
37-
(0%) admin/tool-votes.js - WARNING: uncovered changed runtime JS file; advisory only
38-
(0%) src/dev-runtime/guest-seeds/tool-state-samples.js - WARNING: uncovered changed runtime JS file; advisory only
39-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: uncovered changed runtime JS file; advisory only
40-
(0%) src/dev-runtime/server/mock-api-router.mjs - WARNING: uncovered changed runtime JS file; advisory only
27+
(0%) toolbox/colors/colors.js - WARNING: uncovered changed runtime JS file; advisory only
28+
(0%) toolbox/tools-page-accordions.js - WARNING: uncovered changed runtime JS file; advisory only
4129

4230
Changed JS files considered:
43-
(0%) admin/tool-votes.js - changed JS file not collected as browser runtime coverage
44-
(0%) src/dev-runtime/guest-seeds/tool-state-samples.js - changed JS file not collected as browser runtime coverage
45-
(0%) src/dev-runtime/persistence/mock-db-store.js - changed JS file not collected as browser runtime coverage
46-
(0%) src/dev-runtime/server/mock-api-router.mjs - changed JS file not collected as browser runtime coverage
47-
(0%) tests/helpers/playwrightV8CoverageReporter.mjs - changed JS file not collected as browser runtime coverage
4831
(0%) tests/playwright/tools/ToolboxRoutePages.spec.mjs - changed JS file not collected as browser runtime coverage
49-
(50%) src/engine/api/toolbox-votes-api-client.js - changed JS file with browser V8 coverage
50-
(85%) toolbox/tools-page-accordions.js - changed JS file with browser V8 coverage
32+
(0%) toolbox/colors/colors.js - changed JS file not collected as browser runtime coverage
33+
(0%) toolbox/tools-page-accordions.js - changed JS file not collected as browser runtime coverage

tests/playwright/tools/ToolboxRoutePages.spec.mjs

Lines changed: 152 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect, test } from "@playwright/test";
22
import { MOCK_DB_KEYS } from "../../../src/dev-runtime/persistence/mock-db-store.js";
3+
import { getActiveToolRegistry } from "../../../toolbox/toolRegistry.js";
34
import { isBrowserExtensionNoise } from "../../helpers/browserExtensionNoise.mjs";
45
import { startRepoServer } from "../../helpers/playwrightRepoServer.mjs";
56
import { workspaceV2CoverageReporter } from "../../helpers/workspaceV2CoverageReporter.mjs";
@@ -13,6 +14,7 @@ const TOOL_ROUTE_SMOKE_CASES = [
1314
{ heading: "Saved Data", route: "/tools/saved-data/index.html" },
1415
{ heading: "Languages", route: "/tools/languages/index.html" },
1516
];
17+
const REGISTRY_BY_ID = new Map(getActiveToolRegistry().map((tool) => [tool.id, tool]));
1618

1719
test.afterAll(async () => {
1820
await workspaceV2CoverageReporter.writeReport();
@@ -392,7 +394,7 @@ test("toolbox status kickers, filters, card order, and voting controls work from
392394
}
393395
});
394396

395-
test("toolbox Build Path status filters show registry-matched tool rows", async ({ page }) => {
397+
test("toolbox Build Path status filters support multi-select registry-matched tool rows", async ({ page }) => {
396398
const server = await startRepoServer();
397399
const failedRequests = [];
398400
const pageErrors = [];
@@ -418,52 +420,180 @@ test("toolbox Build Path status filters show registry-matched tool rows", async
418420
}
419421
});
420422

421-
async function expectBuildPathChannel(channel, expectedCount) {
423+
async function expectActiveFilters(activeChannels) {
424+
for (const releaseChannel of ["planned", "wireframe", "beta", "complete"]) {
425+
const filter = page.locator(`[data-toolbox-status-filter='${releaseChannel}']`);
426+
const active = activeChannels.includes(releaseChannel);
427+
await expect(filter).toHaveAttribute("aria-pressed", String(active));
428+
if (active) {
429+
await expect(filter).toHaveClass(/primary/);
430+
} else {
431+
await expect(filter).not.toHaveClass(/primary/);
432+
}
433+
}
434+
}
435+
436+
async function expectBuildPathChannels(expectedChannels, expectedCount) {
422437
await expect(page.locator("[data-build-path-tool]")).toHaveCount(expectedCount);
423438
await expect(page.locator("[data-build-path-release-channel]")).toHaveCount(expectedCount);
424439
const releaseChannels = await page.locator("[data-build-path-release-channel]").evaluateAll((rows) => (
425440
rows.map((row) => row.getAttribute("data-build-path-release-channel"))
426441
));
427-
expect(releaseChannels.every((releaseChannel) => releaseChannel === channel)).toBe(true);
442+
expect(releaseChannels.every((releaseChannel) => expectedChannels.includes(releaseChannel))).toBe(true);
428443
}
429444

430-
async function selectBuildPathFilter(channel) {
431-
await page.locator(`[data-toolbox-status-filter='${channel}']`).click();
432-
for (const releaseChannel of ["planned", "wireframe", "beta", "complete"]) {
433-
await expect(page.locator(`[data-toolbox-status-filter='${releaseChannel}']`)).toHaveAttribute(
434-
"aria-pressed",
435-
String(releaseChannel === channel),
436-
);
437-
}
445+
async function expectBuildPathOrder(toolTitle, expectedOrder) {
446+
await expect(page.locator(`[data-build-path-tool='${toolTitle}'] td`).first()).toHaveText(String(expectedOrder));
438447
}
439448

440449
try {
441450
await workspaceV2CoverageReporter.start(page);
442451
await setServerSession(server, MOCK_DB_KEYS.users.user1);
443452
await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" });
453+
await expect(page.locator("[data-tools-order]")).toHaveClass(/primary/);
454+
await page.locator("[data-tools-sort='grouped']").click();
455+
await expect(page.locator("[data-tools-sort='grouped']")).toHaveClass(/primary/);
444456
await page.locator("[data-tools-view='build-path']").click();
457+
await expect(page.locator("[data-tools-view='build-path']")).toHaveClass(/primary/);
458+
await expect(page.locator("[data-tools-order]")).not.toHaveClass(/primary/);
459+
await expect(page.locator("[data-tools-sort='grouped']")).not.toHaveClass(/primary/);
445460

446461
await expect(page.locator("[data-toolbox-status-filter]")).toHaveText([
447462
"Planned (28)",
448463
"Wireframe (4)",
449464
"Beta (5)",
450465
"Complete (1)",
451466
]);
452-
await expect(page.locator("[data-toolbox-status-filter='planned']")).toHaveAttribute("aria-pressed", "false");
453-
await expect(page.locator("[data-toolbox-status-filter='wireframe']")).toHaveAttribute("aria-pressed", "false");
454-
await expect(page.locator("[data-toolbox-status-filter='beta']")).toHaveAttribute("aria-pressed", "false");
455-
await expect(page.locator("[data-toolbox-status-filter='complete']")).toHaveAttribute("aria-pressed", "true");
467+
await expectActiveFilters(["complete"]);
456468
await expect(page.locator("[data-build-path-tool='Colors']")).toBeVisible();
457-
await expectBuildPathChannel("complete", 1);
469+
await expectBuildPathChannels(["complete"], 1);
470+
await expectBuildPathOrder("Colors", REGISTRY_BY_ID.get("colors").order);
471+
472+
await page.locator("[data-toolbox-status-filter='planned']").click();
473+
await expectActiveFilters(["planned", "complete"]);
474+
await expectBuildPathChannels(["planned", "complete"], 29);
475+
await expect(page.locator("[data-build-path-tool='AI Assistant']")).toBeVisible();
476+
await expectBuildPathOrder("AI Assistant", REGISTRY_BY_ID.get("ai-assistant").order);
477+
await expectBuildPathOrder("Colors", REGISTRY_BY_ID.get("colors").order);
478+
479+
await page.locator("[data-toolbox-status-filter='complete']").click();
480+
await expectActiveFilters(["planned"]);
481+
await expectBuildPathChannels(["planned"], 28);
482+
await expect(page.locator("[data-build-path-tool='Colors']")).toHaveCount(0);
483+
await expect(page.locator("[data-build-path-tool='AI Assistant']")).toBeVisible();
484+
485+
await page.locator("[data-toolbox-status-filter='wireframe']").click();
486+
await expectActiveFilters(["planned", "wireframe"]);
487+
await expectBuildPathChannels(["planned", "wireframe"], 32);
488+
await expect(page.locator("[data-build-path-tool='Build Game']")).toBeVisible();
489+
await expectBuildPathOrder("Build Game", REGISTRY_BY_ID.get("build-game").order);
490+
491+
await page.locator("[data-toolbox-status-filter='beta']").click();
492+
await expectActiveFilters(["planned", "wireframe", "beta"]);
493+
await expectBuildPathChannels(["planned", "wireframe", "beta"], 37);
494+
495+
expect(failedRequests).toEqual([]);
496+
expect(pageErrors).toEqual([]);
497+
expect(consoleErrors).toEqual([]);
498+
} finally {
499+
await workspaceV2CoverageReporter.stop(page);
500+
await server.close();
501+
}
502+
});
503+
504+
test("Colors Picker Preview header controls update live and reset to defaults", async ({ page }) => {
505+
const server = await startRepoServer();
506+
const failedRequests = [];
507+
const pageErrors = [];
508+
const consoleErrors = [];
458509

459-
await selectBuildPathFilter("planned");
460-
await expectBuildPathChannel("planned", 28);
510+
page.on("response", (response) => {
511+
if (response.status() >= 400) {
512+
failedRequests.push(`${response.status()} ${response.url()}`);
513+
}
514+
});
515+
page.on("requestfailed", (request) => {
516+
failedRequests.push(`FAILED ${request.url()}`);
517+
});
518+
page.on("pageerror", (error) => {
519+
const text = error.stack || error.message;
520+
if (!isBrowserExtensionNoise(text)) {
521+
pageErrors.push(error.message);
522+
}
523+
});
524+
page.on("console", (message) => {
525+
if (message.type() === "error" && !isBrowserExtensionNoise(message.text())) {
526+
consoleErrors.push(message.text());
527+
}
528+
});
529+
530+
async function setSlider(selector, value) {
531+
await page.locator(selector).evaluate((input, nextValue) => {
532+
input.value = String(nextValue);
533+
input.dispatchEvent(new Event("input", { bubbles: true }));
534+
}, value);
535+
}
461536

462-
await selectBuildPathFilter("wireframe");
463-
await expectBuildPathChannel("wireframe", 4);
537+
async function firstPreviewFill() {
538+
return page.locator("[data-palette-generator-preview-row]")
539+
.first()
540+
.locator("[data-palette-generator-swatch]")
541+
.first()
542+
.locator("rect")
543+
.getAttribute("fill");
544+
}
464545

465-
await selectBuildPathFilter("beta");
466-
await expectBuildPathChannel("beta", 5);
546+
try {
547+
await workspaceV2CoverageReporter.start(page);
548+
await setServerSession(server, MOCK_DB_KEYS.users.user1);
549+
await page.goto(`${server.baseUrl}/toolbox/colors/index.html`, { waitUntil: "networkidle" });
550+
551+
const previewSummary = page.locator("[data-palette-preview-accordion] summary");
552+
const summaryOrder = await previewSummary.evaluate((summary) => (
553+
Array.from(summary.children).map((child) => {
554+
if (child.hasAttribute("data-palette-preview-controls")) return "preview-controls";
555+
if (child.querySelector("[data-palette-generator-preview-status]")) return "preview-status";
556+
return child.textContent.trim();
557+
})
558+
));
559+
expect(summaryOrder).toEqual(["Picker Preview", "preview-controls", "preview-status"]);
560+
561+
const previewControls = page.locator("[data-palette-preview-controls]");
562+
await expect(previewControls.locator("[data-palette-preview-hue]")).toBeVisible();
563+
await expect(previewControls.locator("[data-palette-preview-saturation]")).toBeVisible();
564+
await expect(previewControls.locator("[data-palette-preview-brightness]")).toBeVisible();
565+
await expect(previewControls.locator("[data-palette-preview-reset]")).toHaveText("Default");
566+
await expect(page.locator("[data-palette-preview-hue-value]")).toContainText("0");
567+
await expect(page.locator("[data-palette-preview-saturation-value]")).toHaveText("100%");
568+
await expect(page.locator("[data-palette-preview-brightness-value]")).toHaveText("100%");
569+
570+
await expect(page.locator("[data-palette-generator-swatch]").first()).toBeVisible();
571+
const initialFill = await firstPreviewFill();
572+
await setSlider("[data-palette-preview-hue]", 45);
573+
await expect(page.locator("[data-palette-preview-hue-value]")).toContainText("+45");
574+
await expect.poll(firstPreviewFill).not.toBe(initialFill);
575+
const hueAdjustedFill = await firstPreviewFill();
576+
577+
await setSlider("[data-palette-preview-saturation]", 50);
578+
await expect(page.locator("[data-palette-preview-saturation-value]")).toHaveText("50%");
579+
await expect.poll(firstPreviewFill).not.toBe(hueAdjustedFill);
580+
const saturationAdjustedFill = await firstPreviewFill();
581+
582+
await setSlider("[data-palette-preview-brightness]", 75);
583+
await expect(page.locator("[data-palette-preview-brightness-value]")).toHaveText("75%");
584+
await expect.poll(firstPreviewFill).not.toBe(saturationAdjustedFill);
585+
586+
await page.locator("[data-palette-preview-hue]").dblclick();
587+
await expect(page.locator("[data-palette-preview-hue-value]")).toContainText("0");
588+
589+
await setSlider("[data-palette-preview-hue]", 90);
590+
await setSlider("[data-palette-preview-saturation]", 25);
591+
await setSlider("[data-palette-preview-brightness]", 125);
592+
await page.locator("[data-palette-preview-reset]").click();
593+
await expect(page.locator("[data-palette-preview-hue-value]")).toContainText("0");
594+
await expect(page.locator("[data-palette-preview-saturation-value]")).toHaveText("100%");
595+
await expect(page.locator("[data-palette-preview-brightness-value]")).toHaveText("100%");
596+
await expect(page.locator("[data-palette-preview-accordion]")).toHaveJSProperty("open", true);
467597

468598
expect(failedRequests).toEqual([]);
469599
expect(pageErrors).toEqual([]);

0 commit comments

Comments
 (0)