mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
✨ Select boards to export to PDF
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
### :heart: Community contributions (Thank you!)
|
### :heart: Community contributions (Thank you!)
|
||||||
|
|
||||||
### :sparkles: New features & Enhancements
|
### :sparkles: New features & Enhancements
|
||||||
|
- Select boards to export as PDF [Taiga #12320](https://tree.taiga.io/project/penpot/issue/12320)
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
|||||||
403
frontend/playwright/data/workspace/get-file-export-frames.json
Normal file
403
frontend/playwright/data/workspace/get-file-export-frames.json
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
{
|
||||||
|
"~:features": {
|
||||||
|
"~#set": [
|
||||||
|
"fdata/path-data",
|
||||||
|
"plugins/runtime",
|
||||||
|
"design-tokens/v1",
|
||||||
|
"variants/v1",
|
||||||
|
"layout/grid",
|
||||||
|
"styles/v2",
|
||||||
|
"fdata/pointer-map",
|
||||||
|
"fdata/objects-map",
|
||||||
|
"components/v2",
|
||||||
|
"fdata/shape-data-type"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"~:team-id": "~u5d1327cf-3054-8111-8005-328a160ff966",
|
||||||
|
"~:permissions": {
|
||||||
|
"~:type": "~:membership",
|
||||||
|
"~:is-owner": true,
|
||||||
|
"~:is-admin": true,
|
||||||
|
"~:can-edit": true,
|
||||||
|
"~:can-read": true,
|
||||||
|
"~:is-logged": true
|
||||||
|
},
|
||||||
|
"~:has-media-trimmed": false,
|
||||||
|
"~:comment-thread-seqn": 0,
|
||||||
|
"~:name": "New File 5",
|
||||||
|
"~:revn": 4,
|
||||||
|
"~:modified-at": "~m1761108835447",
|
||||||
|
"~:vern": 0,
|
||||||
|
"~:id": "~u8d102c33-b98f-81f6-8006-fdd4ea9780d7",
|
||||||
|
"~:is-shared": false,
|
||||||
|
"~:migrations": {
|
||||||
|
"~#ordered-set": [
|
||||||
|
"legacy-2",
|
||||||
|
"legacy-3",
|
||||||
|
"legacy-5",
|
||||||
|
"legacy-6",
|
||||||
|
"legacy-7",
|
||||||
|
"legacy-8",
|
||||||
|
"legacy-9",
|
||||||
|
"legacy-10",
|
||||||
|
"legacy-11",
|
||||||
|
"legacy-12",
|
||||||
|
"legacy-13",
|
||||||
|
"legacy-14",
|
||||||
|
"legacy-16",
|
||||||
|
"legacy-17",
|
||||||
|
"legacy-18",
|
||||||
|
"legacy-19",
|
||||||
|
"legacy-25",
|
||||||
|
"legacy-26",
|
||||||
|
"legacy-27",
|
||||||
|
"legacy-28",
|
||||||
|
"legacy-29",
|
||||||
|
"legacy-31",
|
||||||
|
"legacy-32",
|
||||||
|
"legacy-33",
|
||||||
|
"legacy-34",
|
||||||
|
"legacy-36",
|
||||||
|
"legacy-37",
|
||||||
|
"legacy-38",
|
||||||
|
"legacy-39",
|
||||||
|
"legacy-40",
|
||||||
|
"legacy-41",
|
||||||
|
"legacy-42",
|
||||||
|
"legacy-43",
|
||||||
|
"legacy-44",
|
||||||
|
"legacy-45",
|
||||||
|
"legacy-46",
|
||||||
|
"legacy-47",
|
||||||
|
"legacy-48",
|
||||||
|
"legacy-49",
|
||||||
|
"legacy-50",
|
||||||
|
"legacy-51",
|
||||||
|
"legacy-52",
|
||||||
|
"legacy-53",
|
||||||
|
"legacy-54",
|
||||||
|
"legacy-55",
|
||||||
|
"legacy-56",
|
||||||
|
"legacy-57",
|
||||||
|
"legacy-59",
|
||||||
|
"legacy-62",
|
||||||
|
"legacy-65",
|
||||||
|
"legacy-66",
|
||||||
|
"legacy-67",
|
||||||
|
"0001-remove-tokens-from-groups",
|
||||||
|
"0002-normalize-bool-content-v2",
|
||||||
|
"0002-clean-shape-interactions",
|
||||||
|
"0003-fix-root-shape",
|
||||||
|
"0003-convert-path-content-v2",
|
||||||
|
"0004-clean-shadow-color",
|
||||||
|
"0005-deprecate-image-type",
|
||||||
|
"0006-fix-old-texts-fills",
|
||||||
|
"0008-fix-library-colors-v4",
|
||||||
|
"0009-clean-library-colors",
|
||||||
|
"0009-add-partial-text-touched-flags",
|
||||||
|
"0010-fix-swap-slots-pointing-non-existent-shapes",
|
||||||
|
"0011-fix-invalid-text-touched-flags",
|
||||||
|
"0012-fix-position-data",
|
||||||
|
"0013-fix-component-path",
|
||||||
|
"0013-clear-invalid-strokes-and-fills",
|
||||||
|
"0014-fix-tokens-lib-duplicate-ids",
|
||||||
|
"0014-clear-components-nil-objects"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"~:version": 67,
|
||||||
|
"~:project-id": "~u5d1327cf-3054-8111-8005-328a161446c2",
|
||||||
|
"~:created-at": "~m1761108772446",
|
||||||
|
"~:backend": "legacy-db",
|
||||||
|
"~:data": {
|
||||||
|
"~:pages": [
|
||||||
|
"~u8d102c33-b98f-81f6-8006-fdd4ea9780d8"
|
||||||
|
],
|
||||||
|
"~:pages-index": {
|
||||||
|
"~u8d102c33-b98f-81f6-8006-fdd4ea9780d8": {
|
||||||
|
"~:objects": {
|
||||||
|
"~u00000000-0000-0000-0000-000000000000": {
|
||||||
|
"~#shape": {
|
||||||
|
"~:y": 0,
|
||||||
|
"~:hide-fill-on-export": false,
|
||||||
|
"~:transform": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1,
|
||||||
|
"~:b": 0,
|
||||||
|
"~:c": 0,
|
||||||
|
"~:d": 1,
|
||||||
|
"~:e": 0,
|
||||||
|
"~:f": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:rotation": 0,
|
||||||
|
"~:name": "Root Frame",
|
||||||
|
"~:width": 0.01,
|
||||||
|
"~:type": "~:frame",
|
||||||
|
"~:points": [
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0,
|
||||||
|
"~:y": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0.01,
|
||||||
|
"~:y": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0.01,
|
||||||
|
"~:y": 0.01
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0,
|
||||||
|
"~:y": 0.01
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:r2": 0,
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1,
|
||||||
|
"~:b": 0,
|
||||||
|
"~:c": 0,
|
||||||
|
"~:d": 1,
|
||||||
|
"~:e": 0,
|
||||||
|
"~:f": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:r3": 0,
|
||||||
|
"~:r1": 0,
|
||||||
|
"~:id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:strokes": [],
|
||||||
|
"~:x": 0,
|
||||||
|
"~:proportion": 1,
|
||||||
|
"~:r4": 0,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 0,
|
||||||
|
"~:y": 0,
|
||||||
|
"~:width": 0.01,
|
||||||
|
"~:height": 0.01,
|
||||||
|
"~:x1": 0,
|
||||||
|
"~:y1": 0,
|
||||||
|
"~:x2": 0.01,
|
||||||
|
"~:y2": 0.01
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:fills": [
|
||||||
|
{
|
||||||
|
"~:fill-color": "#FFFFFF",
|
||||||
|
"~:fill-opacity": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:flip-x": null,
|
||||||
|
"~:height": 0.01,
|
||||||
|
"~:flip-y": null,
|
||||||
|
"~:shapes": [
|
||||||
|
"~uc4dbee46-cbea-80d3-8006-fdd4ed673ac9",
|
||||||
|
"~uc4dbee46-cbea-80d3-8006-fdd4efef17bb"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~uc4dbee46-cbea-80d3-8006-fdd4ed673ac9": {
|
||||||
|
"~#shape": {
|
||||||
|
"~:y": 296,
|
||||||
|
"~:hide-fill-on-export": false,
|
||||||
|
"~:transform": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1,
|
||||||
|
"~:b": 0,
|
||||||
|
"~:c": 0,
|
||||||
|
"~:d": 1,
|
||||||
|
"~:e": 0,
|
||||||
|
"~:f": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:rotation": 0,
|
||||||
|
"~:grow-type": "~:fixed",
|
||||||
|
"~:hide-in-viewer": false,
|
||||||
|
"~:name": "Board 1",
|
||||||
|
"~:width": 190,
|
||||||
|
"~:type": "~:frame",
|
||||||
|
"~:points": [
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 624,
|
||||||
|
"~:y": 296
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 814,
|
||||||
|
"~:y": 296
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 814,
|
||||||
|
"~:y": 496
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 624,
|
||||||
|
"~:y": 496
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:r2": 0,
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1,
|
||||||
|
"~:b": 0,
|
||||||
|
"~:c": 0,
|
||||||
|
"~:d": 1,
|
||||||
|
"~:e": 0,
|
||||||
|
"~:f": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:r3": 0,
|
||||||
|
"~:r1": 0,
|
||||||
|
"~:id": "~uc4dbee46-cbea-80d3-8006-fdd4ed673ac9",
|
||||||
|
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:strokes": [],
|
||||||
|
"~:x": 624,
|
||||||
|
"~:proportion": 1,
|
||||||
|
"~:r4": 0,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 624,
|
||||||
|
"~:y": 296,
|
||||||
|
"~:width": 190,
|
||||||
|
"~:height": 200,
|
||||||
|
"~:x1": 624,
|
||||||
|
"~:y1": 296,
|
||||||
|
"~:x2": 814,
|
||||||
|
"~:y2": 496
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:fills": [
|
||||||
|
{
|
||||||
|
"~:fill-color": "#410bb2",
|
||||||
|
"~:fill-opacity": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:flip-x": null,
|
||||||
|
"~:height": 200,
|
||||||
|
"~:flip-y": null,
|
||||||
|
"~:shapes": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~uc4dbee46-cbea-80d3-8006-fdd4efef17bb": {
|
||||||
|
"~#shape": {
|
||||||
|
"~:y": 383,
|
||||||
|
"~:hide-fill-on-export": false,
|
||||||
|
"~:transform": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1,
|
||||||
|
"~:b": 0,
|
||||||
|
"~:c": 0,
|
||||||
|
"~:d": 1,
|
||||||
|
"~:e": 0,
|
||||||
|
"~:f": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:rotation": 0,
|
||||||
|
"~:grow-type": "~:fixed",
|
||||||
|
"~:hide-in-viewer": false,
|
||||||
|
"~:name": "Board 2",
|
||||||
|
"~:width": 226,
|
||||||
|
"~:type": "~:frame",
|
||||||
|
"~:points": [
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 1117,
|
||||||
|
"~:y": 383
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 1343,
|
||||||
|
"~:y": 383
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 1343,
|
||||||
|
"~:y": 618
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 1117,
|
||||||
|
"~:y": 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:r2": 0,
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1,
|
||||||
|
"~:b": 0,
|
||||||
|
"~:c": 0,
|
||||||
|
"~:d": 1,
|
||||||
|
"~:e": 0,
|
||||||
|
"~:f": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:r3": 0,
|
||||||
|
"~:r1": 0,
|
||||||
|
"~:id": "~uc4dbee46-cbea-80d3-8006-fdd4efef17bb",
|
||||||
|
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:strokes": [],
|
||||||
|
"~:x": 1117,
|
||||||
|
"~:proportion": 1,
|
||||||
|
"~:r4": 0,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 1117,
|
||||||
|
"~:y": 383,
|
||||||
|
"~:width": 226,
|
||||||
|
"~:height": 235,
|
||||||
|
"~:x1": 1117,
|
||||||
|
"~:y1": 383,
|
||||||
|
"~:x2": 1343,
|
||||||
|
"~:y2": 618
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:fills": [
|
||||||
|
{
|
||||||
|
"~:fill-color": "#e30808",
|
||||||
|
"~:fill-opacity": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:flip-x": null,
|
||||||
|
"~:height": 235,
|
||||||
|
"~:flip-y": null,
|
||||||
|
"~:shapes": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:id": "~u8d102c33-b98f-81f6-8006-fdd4ea9780d8",
|
||||||
|
"~:name": "Page 1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:id": "~u8d102c33-b98f-81f6-8006-fdd4ea9780d7",
|
||||||
|
"~:options": {
|
||||||
|
"~:components-v2": true,
|
||||||
|
"~:base-font-size": "16px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
191
frontend/playwright/ui/specs/export-frames.spec.js
Normal file
191
frontend/playwright/ui/specs/export-frames.spec.js
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
import { WorkspacePage } from "../pages/WorkspacePage";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await WorkspacePage.init(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to setup workspace with frames for export testing
|
||||||
|
*/
|
||||||
|
async function setupWorkspaceWithFrames(workspacePage) {
|
||||||
|
await workspacePage.setupEmptyFile();
|
||||||
|
await workspacePage.mockRPC(
|
||||||
|
/get\-file\?/,
|
||||||
|
"workspace/get-file-export-frames.json",
|
||||||
|
);
|
||||||
|
await workspacePage.mockRPC(
|
||||||
|
"get-file-object-thumbnails?file-id=*",
|
||||||
|
"workspace/get-file-object-thumbnails-blank.json",
|
||||||
|
);
|
||||||
|
await workspacePage.mockRPC(
|
||||||
|
"get-file-fragment?file-id=*",
|
||||||
|
"workspace/get-file-fragment-blank.json",
|
||||||
|
);
|
||||||
|
await workspacePage.goToWorkspace({
|
||||||
|
fileId: "8d102c33-b98f-81f6-8006-fdd4ea9780d7",
|
||||||
|
pageId: "8d102c33-b98f-81f6-8006-fdd4ea9780d8",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test.describe("Export frames to PDF", () => {
|
||||||
|
test("Export frames menu option is NOT visible when page has no frames", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await workspacePage.setupEmptyFile();
|
||||||
|
|
||||||
|
await workspacePage.goToWorkspace();
|
||||||
|
|
||||||
|
// Open main menu
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("file").last().click();
|
||||||
|
|
||||||
|
// The "Export frames to PDF" option should NOT be visible when there are no frames
|
||||||
|
await expect(
|
||||||
|
page.locator("#file-menu-export-frames"),
|
||||||
|
).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Export frames menu option is visible when there are frames (even if not selected)", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await setupWorkspaceWithFrames(workspacePage);
|
||||||
|
|
||||||
|
// Open main menu
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("file").last().click();
|
||||||
|
|
||||||
|
// The "Export frames to PDF" option should be visible when there are frames on the page
|
||||||
|
await expect(
|
||||||
|
page.locator("#file-menu-export-frames"),
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Export frames modal shows all frames when none are selected", async ({ page }) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await setupWorkspaceWithFrames(workspacePage);
|
||||||
|
|
||||||
|
// Don't select any frame
|
||||||
|
|
||||||
|
// Open main menu
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("file").last().click();
|
||||||
|
|
||||||
|
// Click on "Export frames to PDF"
|
||||||
|
await page.locator("#file-menu-export-frames").click();
|
||||||
|
|
||||||
|
// The modal title should be correct
|
||||||
|
await expect(page.getByText("Export as PDF")).toBeVisible();
|
||||||
|
|
||||||
|
// Both frames should appear in the list
|
||||||
|
await expect(page.getByRole("button", { name: "Board 1" })).toBeVisible();
|
||||||
|
await expect(page.getByRole("button", { name: "Board 2" })).toBeVisible();
|
||||||
|
|
||||||
|
// The selection counter should show "2 of 2"
|
||||||
|
await expect(page.getByText("2 of 2 elements selected")).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Export frames modal shows only the selected frames", async ({ page }) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await setupWorkspaceWithFrames(workspacePage);
|
||||||
|
|
||||||
|
// Select Frame 1
|
||||||
|
await workspacePage.clickLeafLayer("Board 1");
|
||||||
|
|
||||||
|
// Open main menu
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("file").last().click();
|
||||||
|
|
||||||
|
// Click on "Export frames to PDF"
|
||||||
|
await page.locator("#file-menu-export-frames").click();
|
||||||
|
|
||||||
|
// The modal title should be correct
|
||||||
|
await expect(page.getByText("Export as PDF")).toBeVisible();
|
||||||
|
|
||||||
|
// Only Frame 1 should appear in the list
|
||||||
|
// await page.getByRole("button", { name: "Board 1" }),
|
||||||
|
await expect(page.getByRole("button", { name: "Board 1" })).toBeVisible();
|
||||||
|
await expect(page.getByRole("button", { name: "Board 2" })).not.toBeVisible();
|
||||||
|
|
||||||
|
// The selection counter should show "1 of 1"
|
||||||
|
await expect(page.getByText("1 of 1 elements selected")).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("User can deselect frames in the export modal", async ({ page }) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await setupWorkspaceWithFrames(workspacePage);
|
||||||
|
|
||||||
|
// Select Frame 1
|
||||||
|
await workspacePage.clickLeafLayer("Board 1");
|
||||||
|
|
||||||
|
// Add Frame 2 to selection
|
||||||
|
await page.keyboard.down("Shift");
|
||||||
|
await workspacePage.clickLeafLayer("Board 2");
|
||||||
|
await page.keyboard.up("Shift");
|
||||||
|
|
||||||
|
// Open main menu and click export
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("file").last().click();
|
||||||
|
await page.locator("#file-menu-export-frames").click();
|
||||||
|
|
||||||
|
// The modal should appear with 2 frames
|
||||||
|
await expect(page.getByText("2 of 2 elements selected")).toBeVisible();
|
||||||
|
|
||||||
|
// Click on the checkbox next to Frame 1 to deselect it
|
||||||
|
await page.getByRole("button", { name: "Board 1" }).click();
|
||||||
|
|
||||||
|
// Now only 1 frame should be selected
|
||||||
|
await expect(page.getByText("1 of 2 elements selected")).toBeVisible();
|
||||||
|
|
||||||
|
// The export button should still be enabled
|
||||||
|
const exportButton = page.locator("input[type='button'][value='Export']");
|
||||||
|
await expect(exportButton).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Export button is disabled when all frames are deselected", async ({ page }) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await setupWorkspaceWithFrames(workspacePage);
|
||||||
|
|
||||||
|
// Select Frame 1
|
||||||
|
await workspacePage.clickLeafLayer("Board 1");
|
||||||
|
|
||||||
|
// Open main menu and click export
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("file").last().click();
|
||||||
|
await page.locator("#file-menu-export-frames").click();
|
||||||
|
|
||||||
|
// Deselect the frame
|
||||||
|
await page.getByRole("button", { name: "Board 1" }).click();
|
||||||
|
|
||||||
|
// Now 0 frames are selected
|
||||||
|
await expect(page.getByText("0 of 1 elements selected")).toBeVisible();
|
||||||
|
|
||||||
|
// // The export button should be disabled
|
||||||
|
await expect(page.getByRole("button", { name: "Export" , exact: true})).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("User can cancel the export modal", async ({ page }) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await setupWorkspaceWithFrames(workspacePage);
|
||||||
|
|
||||||
|
// Select Frame 1
|
||||||
|
await workspacePage.clickLeafLayer("Board 1");
|
||||||
|
|
||||||
|
// Open main menu and click export
|
||||||
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
|
await page.getByText("file").last().click();
|
||||||
|
await page.locator("#file-menu-export-frames").click();
|
||||||
|
|
||||||
|
// Now only 1 frame should be selected
|
||||||
|
await expect(page.getByText("1 of 1 elements selected")).toBeVisible();
|
||||||
|
|
||||||
|
// Click cancel
|
||||||
|
await page.getByRole("button", { name: "Cancel" }).click();
|
||||||
|
|
||||||
|
// The modal should be hidden
|
||||||
|
await expect(page.getByText("0 of 1 elements selected")).not.toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@@ -519,9 +519,14 @@
|
|||||||
shared? (:is-shared file)
|
shared? (:is-shared file)
|
||||||
|
|
||||||
objects (mf/deref refs/workspace-page-objects)
|
objects (mf/deref refs/workspace-page-objects)
|
||||||
frames (->> (cfh/get-immediate-children objects uuid/zero)
|
selected (mf/deref refs/selected-shapes)
|
||||||
|
all-frames (->> (cfh/get-immediate-children objects uuid/zero)
|
||||||
(filterv cfh/frame-shape?))
|
(filterv cfh/frame-shape?))
|
||||||
|
|
||||||
|
;; If there are selected frames, use only those. Otherwise, use all frames
|
||||||
|
selected-frames (filterv #(contains? selected (:id %)) all-frames)
|
||||||
|
frames (if (seq selected-frames) selected-frames all-frames)
|
||||||
|
|
||||||
perms (mf/use-ctx ctx/permissions)
|
perms (mf/use-ctx ctx/permissions)
|
||||||
can-edit (:can-edit perms)
|
can-edit (:can-edit perms)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user