mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-30 08:37:56 +09:00
**Summary** Fixes content-mode edit permissions so editor-only users can perform allowed content workflows without backend “build permission” failures. **Changes** - Added shared content-mode permission validation used by backend authorization. - Aligned content-mode capabilities around editable props, editable instances, content roots, pages, assets, and template insertion. - Allowed content-safe instance/text/page/template/style changes while keeping design/data/resource changes build-only. - Updated template insertion to preserve content-safe local styles and reuse tokens by id. - Added accessible `SyncStatusDot` for e2e-visible sync state without replacing the existing sync status UI. - Added builder e2e setup with Postgres/PostgREST and a first content-mode browser test: - edit existing text as an editor-only user - wait for saved state via the sync status dot - reload and verify persistence **Verification** - `pnpm --filter=@webstudio-is/builder test -- sync-status.test.tsx` - `pnpm --filter=@webstudio-is/builder typecheck` - `git diff --check` - `pnpm e2e:builder`
82 lines
1.8 KiB
TypeScript
82 lines
1.8 KiB
TypeScript
import type { Page } from "playwright";
|
|
import { waitForCanvasFrame } from "./builder";
|
|
|
|
const delay = (ms: number) =>
|
|
new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
|
|
export const selectCanvasTextInstanceForProps = async ({
|
|
page,
|
|
text,
|
|
propertyLabel,
|
|
}: {
|
|
page: Page;
|
|
text: string;
|
|
propertyLabel: string;
|
|
}) => {
|
|
const startedAt = Date.now();
|
|
let lastBodyText = "";
|
|
|
|
while (Date.now() - startedAt < 10_000) {
|
|
const canvas = await waitForCanvasFrame({ page });
|
|
await canvas.getByText(text).click();
|
|
await delay(300);
|
|
await page.keyboard.press("Escape");
|
|
|
|
if (
|
|
await page
|
|
.getByText(propertyLabel, { exact: true })
|
|
.first()
|
|
.isVisible({ timeout: 500 })
|
|
.catch(() => false)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
lastBodyText = await page
|
|
.locator("body")
|
|
.innerText()
|
|
.catch(() => "");
|
|
await delay(250);
|
|
}
|
|
|
|
throw new Error(
|
|
`Expected selected canvas text "${text}" to show property "${propertyLabel}". Page text: ${lastBodyText}`
|
|
);
|
|
};
|
|
|
|
export const selectCanvasTextInstance = async ({
|
|
page,
|
|
text,
|
|
}: {
|
|
page: Page;
|
|
text: string;
|
|
}) => {
|
|
const startedAt = Date.now();
|
|
let lastBodyText = "";
|
|
|
|
while (Date.now() - startedAt < 10_000) {
|
|
const canvas = await waitForCanvasFrame({ page });
|
|
await canvas.getByText(text).click();
|
|
await delay(300);
|
|
|
|
if (
|
|
(await page
|
|
.getByText("No instance selected", { exact: true })
|
|
.isVisible({ timeout: 500 })
|
|
.catch(() => false)) === false
|
|
) {
|
|
return;
|
|
}
|
|
|
|
lastBodyText = await page
|
|
.locator("body")
|
|
.innerText()
|
|
.catch(() => "");
|
|
await delay(250);
|
|
}
|
|
|
|
throw new Error(
|
|
`Expected to select canvas text "${text}". Page text: ${lastBodyText}`
|
|
);
|
|
};
|