Skip to content

Commit dbbcc3a

Browse files
author
DavidQ
committed
Compact Object Transform controls into one-line rows and clean summary text - PR_26133_040-object-transform-one-line-control-layout
1 parent 571c0b2 commit dbbcc3a

5 files changed

Lines changed: 243 additions & 79 deletions

File tree

docs/dev/reports/playwright_v8_coverage_report.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# PR_26133_038 Playwright V8 Coverage Report
1+
# PR_26133_040 Playwright V8 Coverage Report
22

3-
Task: PR_26133_038-object-transform-scale-resize-geometry
3+
Task: PR_26133_040-object-transform-one-line-control-layout
44
Date: 2026-05-15
55

66
## Result
@@ -26,7 +26,7 @@ PASS - Coverage reporting was generated during `npm run test:workspace-v2`.
2626
## Changed Runtime JS Coverage
2727

2828
```text
29-
(94%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 4646/4646; executed functions 479/510
29+
(94%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 4709/4709; executed functions 487/516
3030
```
3131

3232
## Changed Test Coverage Note
@@ -43,4 +43,4 @@ PASS - Coverage reporting was generated during `npm run test:workspace-v2`.
4343

4444
## PR-Specific Note
4545

46-
The Workspace V2 run exercised Object Vector Studio V2 live scale preview, scale step buttons, Resize Geometry baking, scale reset, schema validation, transformed selection bounds refresh, and supported shape-tool geometry rewrite paths. Coverage remains advisory only.
46+
The Workspace V2 run exercised Object Vector Studio V2 one-line Move, Origin, Rotate, and Scale transform controls, transform summary rendering, preserved transform actions, and Object Transform no-console-error paths. Coverage remains advisory only.
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# PR_26133_038 Workspace V2 Playwright Results
1+
# PR_26133_040 Workspace V2 Playwright Results
22

3-
Task: PR_26133_038-object-transform-scale-resize-geometry
3+
Task: PR_26133_040-object-transform-one-line-control-layout
44
Date: 2026-05-15
55

66
## Result
@@ -14,15 +14,13 @@ PASS - `npm run test:workspace-v2` completed successfully.
1414

1515
## PR-Specific Coverage
1616

17-
- Verified Object Transform scale controls render on one line in the requested order:
18-
`Scale [--] [-] [scale input] [+] [++] [Resize]`.
19-
- Verified the Resize button keeps visible text `Resize` and tooltip/title `Resize Geometry`.
20-
- Verified invalid scale input is visibly rejected and does not write `scaleX: 0`.
21-
- Verified live scale input updates the Object Preview, JSON details, and transform summary.
22-
- Verified `--`, `-`, `+`, and `++` buttons step scale by 0.10, 0.01, 0.01, and 0.10 respectively.
23-
- Verified Resize Geometry bakes current scale into rectangle geometry, resets scale to 1, and updates transformed selection bounds.
24-
- Added coverage for Resize Geometry across polygon, triangle, line, rectangle, circle, ellipse, arc, and text shapes.
17+
- Verified Object Transform Move controls render on one line as `Move X [input] Y [input] [Move]`.
18+
- Verified Object Transform Origin controls render on one line as `Origin X [input] Y [input] [Apply]`.
19+
- Verified Object Transform Rotate controls render on one line as `Rotate [input] [Rotate]`.
20+
- Verified existing Scale controls remain one line as `Scale [--] [-] [scale input] [+] [++] [Resize]`.
21+
- Verified Move, Origin Apply, and Rotate buttons continue to update the selected shape transform.
22+
- Verified transform summary is horizontally centered and no longer starts with `Transform`.
2523

2624
## Manual Verification Equivalent
2725

28-
Targeted Object Vector Studio V2 browser automation covered the requested scale layout, live preview, geometry resize, transformed bounds refresh, invalid input rejection, and no-console-error checks.
26+
Targeted Object Vector Studio V2 browser automation covered the requested transform row layouts, preserved transform actions, centered summary text, retained Scale row layout, and no-console-error checks.

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 70 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,17 +1812,25 @@ test.describe("Workspace Manager V2 bootstrap", () => {
18121812
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).not.toContainText("Transform");
18131813
await expect(page.locator("#objectVectorStudioV2ObjectDetails #objectVectorStudioV2MoveShapeButton")).toHaveCount(0);
18141814
await expect(page.locator("#objectVectorStudioV2ObjectTransform")).not.toContainText("Selected Shape:");
1815-
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("Transform x 0, y 0, rot 0, scale 1 x 1");
1815+
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("x 0, y 0, rot 0, scale 1 x 1");
18161816
await expect(page.locator("#objectVectorStudioV2ObjectTransform #objectVectorStudioV2MoveShapeButton")).toHaveCount(1);
18171817
const transformSummaryLayout = await page.locator("#objectVectorStudioV2ObjectTransform").evaluate((panel) => {
1818-
const actions = panel.querySelector(".object-vector-studio-v2__shape-actions");
1818+
const scaleRow = panel.querySelector(".object-vector-studio-v2__scale-control-row");
18191819
const summary = panel.querySelector(".object-vector-studio-v2__transform-summary");
1820+
const summaryStyle = getComputedStyle(summary);
18201821
return {
1821-
summaryAfterActions: Boolean(actions && summary && (actions.compareDocumentPosition(summary) & Node.DOCUMENT_POSITION_FOLLOWING)),
1822-
summaryTopAtBottom: summary.getBoundingClientRect().top >= actions.getBoundingClientRect().bottom
1822+
summaryAfterScale: Boolean(scaleRow && summary && (scaleRow.compareDocumentPosition(summary) & Node.DOCUMENT_POSITION_FOLLOWING)),
1823+
summaryCentered: summaryStyle.textAlign === "center",
1824+
summaryStartsWithoutTransform: !summary.textContent.trim().startsWith("Transform"),
1825+
summaryTopAtBottom: summary.getBoundingClientRect().top >= scaleRow.getBoundingClientRect().bottom
18231826
};
18241827
});
1825-
expect(transformSummaryLayout).toEqual({ summaryAfterActions: true, summaryTopAtBottom: true });
1828+
expect(transformSummaryLayout).toEqual({
1829+
summaryAfterScale: true,
1830+
summaryCentered: true,
1831+
summaryStartsWithoutTransform: true,
1832+
summaryTopAtBottom: true
1833+
});
18261834
const transformIconState = await page.locator("#objectVectorStudioV2ObjectTransform").evaluate((panel) => ({
18271835
resize: {
18281836
iconKey: panel.querySelector("#objectVectorStudioV2ResizeShapeButton").dataset.ovsIconKey,
@@ -1872,24 +1880,57 @@ test.describe("Workspace Manager V2 bootstrap", () => {
18721880
"Group",
18731881
"None"
18741882
]);
1875-
const transformFieldLayout = await page.locator("#objectVectorStudioV2ObjectTransform").evaluate((panel) => (
1876-
Array.from(panel.querySelectorAll(".object-vector-studio-v2__edit-field--inline")).map((field) => {
1877-
const label = field.querySelector("span");
1878-
const input = field.querySelector("input");
1879-
const labelRect = label.getBoundingClientRect();
1880-
const inputRect = input.getBoundingClientRect();
1883+
const transformControlLayout = await page.locator("#objectVectorStudioV2ObjectTransform").evaluate((panel) => (
1884+
Array.from(panel.querySelectorAll(".object-vector-studio-v2__transform-control-row")).map((row) => {
1885+
const children = Array.from(row.children);
1886+
const centers = children.map((child) => {
1887+
const rect = child.getBoundingClientRect();
1888+
return Math.round(rect.top + rect.height / 2);
1889+
});
1890+
const button = row.querySelector("button");
18811891
return {
1882-
inline: Math.abs((labelRect.top + labelRect.height / 2) - (inputRect.top + inputRect.height / 2)) < 4 && labelRect.right <= inputRect.left,
1883-
label: label.textContent.trim()
1892+
allOneLine: centers.every((center) => Math.abs(center - centers[0]) <= 2),
1893+
axisLabels: Array.from(row.querySelectorAll(".object-vector-studio-v2__transform-axis-field > span")).map((element) => element.textContent.trim()),
1894+
buttonId: button?.id || "",
1895+
buttonText: button?.textContent.trim() || "",
1896+
buttonTitle: button?.title || "",
1897+
inputIds: Array.from(row.querySelectorAll("input")).map((input) => input.id),
1898+
label: row.querySelector(".object-vector-studio-v2__transform-control-label")?.textContent.trim() || "",
1899+
rowType: row.dataset.transformControlRow
18841900
};
18851901
})
18861902
));
1887-
expect(transformFieldLayout).toEqual([
1888-
{ inline: true, label: "Move X" },
1889-
{ inline: true, label: "Move Y" },
1890-
{ inline: true, label: "Rotate" },
1891-
{ inline: true, label: "Origin X" },
1892-
{ inline: true, label: "Origin Y" }
1903+
expect(transformControlLayout).toEqual([
1904+
{
1905+
allOneLine: true,
1906+
axisLabels: ["X", "Y"],
1907+
buttonId: "objectVectorStudioV2MoveShapeButton",
1908+
buttonText: "Move",
1909+
buttonTitle: "",
1910+
inputIds: ["objectVectorStudioV2MoveXInput", "objectVectorStudioV2MoveYInput"],
1911+
label: "Move",
1912+
rowType: "move"
1913+
},
1914+
{
1915+
allOneLine: true,
1916+
axisLabels: ["X", "Y"],
1917+
buttonId: "objectVectorStudioV2ApplyOriginButton",
1918+
buttonText: "Apply",
1919+
buttonTitle: "Apply Origin",
1920+
inputIds: ["objectVectorStudioV2OriginXInput", "objectVectorStudioV2OriginYInput"],
1921+
label: "Origin",
1922+
rowType: "origin"
1923+
},
1924+
{
1925+
allOneLine: true,
1926+
axisLabels: [],
1927+
buttonId: "objectVectorStudioV2RotateShapeButton",
1928+
buttonText: "Rotate",
1929+
buttonTitle: "",
1930+
inputIds: ["objectVectorStudioV2RotateInput"],
1931+
label: "Rotate",
1932+
rowType: "rotate"
1933+
}
18931934
]);
18941935
const transformBeforeInvalid = await page.evaluate(() => window.__objectVectorStudioV2App.selectedShape().transform);
18951936
await page.locator("#objectVectorStudioV2MoveXInput").fill("");
@@ -2234,6 +2275,12 @@ test.describe("Workspace Manager V2 bootstrap", () => {
22342275
await page.locator("#objectVectorStudioV2RotateShapeButton").click();
22352276
await expect(page.locator("#objectVectorStudioV2JsonDetails")).toContainText('"rotation": 15');
22362277
await expect(page.locator("#statusLog")).toHaveValue(/OK Rotated shape row 0 by 15 degrees\./);
2278+
await page.locator("#objectVectorStudioV2OriginXInput").fill("2");
2279+
await page.locator("#objectVectorStudioV2OriginYInput").fill("-3");
2280+
await page.locator("#objectVectorStudioV2ApplyOriginButton").click();
2281+
const originAfterApply = await page.evaluate(() => window.__objectVectorStudioV2App.selectedShape().transform.origin);
2282+
expect(originAfterApply).toEqual({ x: 2, y: -3 });
2283+
await expect(page.locator("#statusLog")).toHaveValue(/OK Updated shape row 0 origin\/pivot to 2, -3\./);
22372284

22382285
await page.locator("#objectVectorStudioV2ScaleInput").fill("0");
22392286
await expect(page.locator("#objectVectorStudioV2ScaleInput")).toHaveAttribute("aria-invalid", "true");
@@ -2243,7 +2290,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
22432290
await expect(page.locator("#objectVectorStudioV2ScaleInput")).not.toHaveAttribute("aria-invalid", "true");
22442291
await expect(page.locator("#statusLog")).toHaveValue(/OK Scale preview set to 1\.2 for shape row 0\./);
22452292
await expect(page.locator("#objectVectorStudioV2JsonDetails")).toContainText('"scaleX": 1.2');
2246-
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("Transform x 10, y 10, rot 15, scale 1.2 x 1.2");
2293+
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("x 10, y 10, rot 15, scale 1.2 x 1.2");
22472294
const selectionBeforeScaleStep = await page.locator("#objectVectorStudioV2RenderSurface [data-selection-bounds='0']").evaluate((box) => ({
22482295
height: Number(box.getAttribute("height")),
22492296
width: Number(box.getAttribute("width"))
@@ -2295,7 +2342,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
22952342
}
22962343
});
22972344
await expect(page.locator("#objectVectorStudioV2ScaleInput")).toHaveValue("1");
2298-
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("Transform x 10, y 10, rot 15, scale 1 x 1");
2345+
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("x 10, y 10, rot 15, scale 1 x 1");
22992346
await expect(page.locator("#statusLog")).toHaveValue(/OK Resize Geometry applied scale 1\.2 to shape row 0; transform scale reset to 1\./);
23002347

23012348
await page.locator("#objectVectorStudioV2BringForwardButton").click();
@@ -3646,12 +3693,12 @@ test.describe("Workspace Manager V2 bootstrap", () => {
36463693
await page.locator("#objectVectorStudioV2MoveYInput").fill("7");
36473694
await page.locator("#objectVectorStudioV2MoveShapeButton").click();
36483695
await expect(page.locator("#statusLog")).toHaveValue(/OK Moved shape row 0 by 10, 10\./);
3649-
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("Transform x 10, y 10, rot 0, scale 1 x 1");
3696+
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("x 10, y 10, rot 0, scale 1 x 1");
36503697
await page.locator("#objectVectorStudioV2MoveXInput").fill("-5");
36513698
await page.locator("#objectVectorStudioV2MoveYInput").fill("-5");
36523699
await page.locator("#objectVectorStudioV2MoveShapeButton").click();
36533700
await expect(page.locator("#statusLog")).toHaveValue(/OK Moved shape row 0 by -10, -10\./);
3654-
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("Transform x 0, y 0, rot 0, scale 1 x 1");
3701+
await expect(page.locator("#objectVectorStudioV2ObjectTransform .object-vector-studio-v2__transform-summary")).toHaveText("x 0, y 0, rot 0, scale 1 x 1");
36553702

36563703
await page.locator("#objectVectorStudioV2CopyJsonButton").click();
36573704
const copiedPayload = await page.evaluate(() => JSON.parse(sessionStorage.getItem("object-vector-studio-v2.authoring-copied-json")));

0 commit comments

Comments
 (0)