From e9005ee33ab573061f3b6071bfb47d9a6e982ea8 Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Tue, 13 Oct 2026 01:04:39 +0200 Subject: [PATCH 001/153] feat: edit the whole form as one document The question list and the workbench become one column. Each question is a compact row (number, type icon, text on up to 2 lines, a meta line with Required, rules, Hidden and the identifier), groups are sections. The open question is a card in place: text with its format toolbar, choices, then answer type, Required, Settings (this type's settings inline), Rules and a menu. A new question opens with the cursor in its text. Co-Authored-By: Claude Opus 5.5 --- resources/js/Pages/Forms/Edit.vue | 12 +- resources/js/components/AdvancedSettings.vue | 23 --- .../components/Factory/Document/BlockMenu.vue | 99 +++++++++++++ .../Factory/Document/DocumentGroup.vue | 109 ++++++++++++++ .../Factory/Document/DocumentList.vue | 64 ++++++++ .../Factory/Document/DocumentQuestion.vue | 110 ++++++++++++++ .../Factory/Document/FormDocument.vue | 86 +++++++++++ .../Factory/Document/QuestionCard.vue | 123 ++++++++++++++++ .../Factory/Document/QuestionSettings.vue | 91 ++++++++++++ .../Factory/Document/questionSummary.test.ts | 38 +++++ .../Factory/Document/questionSummary.ts | 32 ++++ .../Factory/Document/useAddBlock.ts | 25 ++++ .../Factory/Main/BlockInteractions.vue | 26 ---- .../components/Factory/Main/BlockMessage.vue | 22 --- .../Factory/Main/BlockMetaHeader.vue | 34 ----- .../js/components/Factory/Main/BlockType.vue | 65 --------- .../Factory/Main/ConfigureClicks.vue | 19 +-- .../Factory/Main/ConfigureConsents.vue | 2 +- .../components/Factory/Main/GroupSettings.vue | 24 --- .../js/components/Factory/Main/Workbench.vue | 33 ----- .../Factory/Main/WorkbenchEmpty.vue | 34 ----- .../js/components/Factory/Sidebar/Block.vue | 119 --------------- .../Factory/Sidebar/BlockContainer.vue | 104 ------------- .../Factory/Sidebar/BlockFooter.vue | 89 ----------- .../Factory/Sidebar/BlockInteraction.test.ts | 20 --- .../Factory/Sidebar/BlockInteraction.vue | 33 ----- .../Factory/Sidebar/BlockLogicVisualizer.vue | 79 ---------- .../Factory/Sidebar/ConsentBlockMessage.vue | 11 -- .../Factory/Sidebar/DefaultBlockMessage.vue | 14 -- .../js/components/Factory/Sidebar/Group.vue | 127 ---------------- .../Factory/Sidebar/InsertAfterButton.vue | 21 --- .../components/Factory/Sidebar/Storyboard.vue | 138 ------------------ .../js/components/Factory/sanitize.test.ts | 51 ++++--- resources/js/stores/form.ts | 8 + resources/js/utils/useActiveCard.ts | 15 -- 35 files changed, 820 insertions(+), 1080 deletions(-) delete mode 100644 resources/js/components/AdvancedSettings.vue create mode 100644 resources/js/components/Factory/Document/BlockMenu.vue create mode 100644 resources/js/components/Factory/Document/DocumentGroup.vue create mode 100644 resources/js/components/Factory/Document/DocumentList.vue create mode 100644 resources/js/components/Factory/Document/DocumentQuestion.vue create mode 100644 resources/js/components/Factory/Document/FormDocument.vue create mode 100644 resources/js/components/Factory/Document/QuestionCard.vue create mode 100644 resources/js/components/Factory/Document/QuestionSettings.vue create mode 100644 resources/js/components/Factory/Document/questionSummary.test.ts create mode 100644 resources/js/components/Factory/Document/questionSummary.ts create mode 100644 resources/js/components/Factory/Document/useAddBlock.ts delete mode 100644 resources/js/components/Factory/Main/BlockInteractions.vue delete mode 100644 resources/js/components/Factory/Main/BlockMessage.vue delete mode 100644 resources/js/components/Factory/Main/BlockMetaHeader.vue delete mode 100644 resources/js/components/Factory/Main/BlockType.vue delete mode 100644 resources/js/components/Factory/Main/GroupSettings.vue delete mode 100644 resources/js/components/Factory/Main/Workbench.vue delete mode 100644 resources/js/components/Factory/Main/WorkbenchEmpty.vue delete mode 100644 resources/js/components/Factory/Sidebar/Block.vue delete mode 100644 resources/js/components/Factory/Sidebar/BlockContainer.vue delete mode 100644 resources/js/components/Factory/Sidebar/BlockFooter.vue delete mode 100644 resources/js/components/Factory/Sidebar/BlockInteraction.test.ts delete mode 100644 resources/js/components/Factory/Sidebar/BlockInteraction.vue delete mode 100644 resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue delete mode 100644 resources/js/components/Factory/Sidebar/ConsentBlockMessage.vue delete mode 100644 resources/js/components/Factory/Sidebar/DefaultBlockMessage.vue delete mode 100644 resources/js/components/Factory/Sidebar/Group.vue delete mode 100644 resources/js/components/Factory/Sidebar/InsertAfterButton.vue delete mode 100644 resources/js/components/Factory/Sidebar/Storyboard.vue delete mode 100644 resources/js/utils/useActiveCard.ts diff --git a/resources/js/Pages/Forms/Edit.vue b/resources/js/Pages/Forms/Edit.vue index 35004bde..38120b96 100644 --- a/resources/js/Pages/Forms/Edit.vue +++ b/resources/js/Pages/Forms/Edit.vue @@ -1,20 +1,12 @@ diff --git a/resources/js/components/Factory/Document/BlockMenu.vue b/resources/js/components/Factory/Document/BlockMenu.vue new file mode 100644 index 00000000..d4c9ed2e --- /dev/null +++ b/resources/js/components/Factory/Document/BlockMenu.vue @@ -0,0 +1,99 @@ + + + diff --git a/resources/js/components/Factory/Document/DocumentGroup.vue b/resources/js/components/Factory/Document/DocumentGroup.vue new file mode 100644 index 00000000..e7d8c5eb --- /dev/null +++ b/resources/js/components/Factory/Document/DocumentGroup.vue @@ -0,0 +1,109 @@ + + + diff --git a/resources/js/components/Factory/Document/DocumentList.vue b/resources/js/components/Factory/Document/DocumentList.vue new file mode 100644 index 00000000..5c7f9ba9 --- /dev/null +++ b/resources/js/components/Factory/Document/DocumentList.vue @@ -0,0 +1,64 @@ + + + diff --git a/resources/js/components/Factory/Document/DocumentQuestion.vue b/resources/js/components/Factory/Document/DocumentQuestion.vue new file mode 100644 index 00000000..b6d13989 --- /dev/null +++ b/resources/js/components/Factory/Document/DocumentQuestion.vue @@ -0,0 +1,110 @@ + + + diff --git a/resources/js/components/Factory/Document/FormDocument.vue b/resources/js/components/Factory/Document/FormDocument.vue new file mode 100644 index 00000000..7bc8b322 --- /dev/null +++ b/resources/js/components/Factory/Document/FormDocument.vue @@ -0,0 +1,86 @@ + + + diff --git a/resources/js/components/Factory/Document/QuestionCard.vue b/resources/js/components/Factory/Document/QuestionCard.vue new file mode 100644 index 00000000..adb59563 --- /dev/null +++ b/resources/js/components/Factory/Document/QuestionCard.vue @@ -0,0 +1,123 @@ + + + diff --git a/resources/js/components/Factory/Document/QuestionSettings.vue b/resources/js/components/Factory/Document/QuestionSettings.vue new file mode 100644 index 00000000..0afbb7f7 --- /dev/null +++ b/resources/js/components/Factory/Document/QuestionSettings.vue @@ -0,0 +1,91 @@ + + + diff --git a/resources/js/components/Factory/Document/questionSummary.test.ts b/resources/js/components/Factory/Document/questionSummary.test.ts new file mode 100644 index 00000000..309eccd6 --- /dev/null +++ b/resources/js/components/Factory/Document/questionSummary.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, it } from "vitest"; +import { plainText, questionNumbers } from "./questionSummary"; + +const block = (uuid: string, type = "radio", parent_block: string | null = null) => + ({ uuid, type, parent_block }) as FormBlockModel; + +describe("plain question text", () => { + it("drops tags and keeps a space between paragraphs", () => { + expect( + plainText("

Hi & welcome

How was it?

"), + ).toBe("Hi & welcome How was it?"); + }); + + it("is empty for no text or only an image", () => { + expect(plainText(null)).toBe(""); + expect(plainText('')).toBe(""); + }); +}); + +describe("question numbers", () => { + it("counts on through groups and skips the group itself", () => { + const numbers = questionNumbers([ + block("a"), + block("g", "group"), + block("c"), + block("b", "radio", "g"), + block("b2", "date", "g"), + ]); + + expect(numbers).toEqual({ a: 1, b: 2, b2: 3, c: 4 }); + }); + + it("gives an empty group nothing", () => { + expect(questionNumbers([block("g", "group"), block("a")])).toEqual({ + a: 1, + }); + }); +}); diff --git a/resources/js/components/Factory/Document/questionSummary.ts b/resources/js/components/Factory/Document/questionSummary.ts new file mode 100644 index 00000000..a34648a0 --- /dev/null +++ b/resources/js/components/Factory/Document/questionSummary.ts @@ -0,0 +1,32 @@ +// the text a closed question shows: no HTML, one space where a paragraph ended +export function plainText(html: string | null): string { + if (!html) { + return ""; + } + + const spaced = html.replace(/<\/(p|h[1-6]|li|blockquote)>|/gi, "$& "); + const doc = new DOMParser().parseFromString(spaced, "text/html"); + + return (doc.body.textContent ?? "").replace(/\s+/g, " ").trim(); +} + +// questions count on through groups; a group itself gets no number +export function questionNumbers( + blocks: FormBlockModel[], +): Record { + const numbers: Record = {}; + const inScope = (parent: string | null) => + blocks.filter((block) => (block.parent_block ?? null) === parent); + let next = 1; + + for (const block of inScope(null)) { + const questions = + block.type === "group" ? inScope(block.uuid) : [block]; + + for (const question of questions) { + numbers[question.uuid] = next++; + } + } + + return numbers; +} diff --git a/resources/js/components/Factory/Document/useAddBlock.ts b/resources/js/components/Factory/Document/useAddBlock.ts new file mode 100644 index 00000000..54571c32 --- /dev/null +++ b/resources/js/components/Factory/Document/useAddBlock.ts @@ -0,0 +1,25 @@ +import { nextTick } from "vue"; +import { useForm, useWorkbench } from "@/stores"; + +// a new block opens with the cursor in its text, or in its name for a group +export function useAddBlock() { + const store = useForm(); + const workbench = useWorkbench(); + + const addBlock = async ( + ...args: Parameters + ) => { + await store.createFormBlock(...args); + await nextTick(); + + const block = workbench.block; + const field = + block?.type === "group" + ? `group-${block.uuid}-name` + : `question-${block?.uuid}-text`; + + document.getElementById(field)?.focus(); + }; + + return { addBlock }; +} diff --git a/resources/js/components/Factory/Main/BlockInteractions.vue b/resources/js/components/Factory/Main/BlockInteractions.vue deleted file mode 100644 index 36828819..00000000 --- a/resources/js/components/Factory/Main/BlockInteractions.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Main/BlockMessage.vue b/resources/js/components/Factory/Main/BlockMessage.vue deleted file mode 100644 index 71061471..00000000 --- a/resources/js/components/Factory/Main/BlockMessage.vue +++ /dev/null @@ -1,22 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Main/BlockMetaHeader.vue b/resources/js/components/Factory/Main/BlockMetaHeader.vue deleted file mode 100644 index 597ba426..00000000 --- a/resources/js/components/Factory/Main/BlockMetaHeader.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Main/BlockType.vue b/resources/js/components/Factory/Main/BlockType.vue deleted file mode 100644 index 2de35c6b..00000000 --- a/resources/js/components/Factory/Main/BlockType.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Main/ConfigureClicks.vue b/resources/js/components/Factory/Main/ConfigureClicks.vue index 140dbd03..c8286a2e 100644 --- a/resources/js/components/Factory/Main/ConfigureClicks.vue +++ b/resources/js/components/Factory/Main/ConfigureClicks.vue @@ -9,7 +9,7 @@ @@ -26,7 +26,7 @@ -
+
+ Enter adds a choice.
- - - -
@@ -60,8 +49,6 @@ import { Container, Draggable } from "vue3-smooth-dnd"; import EmptyState from "@/components/EmptyState.vue"; import { useKeyboardNavigation } from "@/components/Factory/utils/useKeyboardNavigation"; import useActiveInteractions from "../Shared/useActiveInteractions"; -import CustomResponseSettings from "./Interactions/CustomResponseSettings.vue"; -import RandomizeResponsesSetting from "./Interactions/RandomizeResponsesSetting.vue"; const workbench = useWorkbench(); const { activeInteractions, editableInteractions } = useActiveInteractions( diff --git a/resources/js/components/Factory/Main/ConfigureConsents.vue b/resources/js/components/Factory/Main/ConfigureConsents.vue index 34b4916e..4fcf211d 100644 --- a/resources/js/components/Factory/Main/ConfigureConsents.vue +++ b/resources/js/components/Factory/Main/ConfigureConsents.vue @@ -9,7 +9,7 @@ diff --git a/resources/js/components/Factory/Main/GroupSettings.vue b/resources/js/components/Factory/Main/GroupSettings.vue deleted file mode 100644 index d67fd920..00000000 --- a/resources/js/components/Factory/Main/GroupSettings.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Main/Workbench.vue b/resources/js/components/Factory/Main/Workbench.vue deleted file mode 100644 index b3d855c9..00000000 --- a/resources/js/components/Factory/Main/Workbench.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Main/WorkbenchEmpty.vue b/resources/js/components/Factory/Main/WorkbenchEmpty.vue deleted file mode 100644 index fffedd28..00000000 --- a/resources/js/components/Factory/Main/WorkbenchEmpty.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/Block.vue b/resources/js/components/Factory/Sidebar/Block.vue deleted file mode 100644 index d9be24dd..00000000 --- a/resources/js/components/Factory/Sidebar/Block.vue +++ /dev/null @@ -1,119 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/BlockContainer.vue b/resources/js/components/Factory/Sidebar/BlockContainer.vue deleted file mode 100644 index 7c417030..00000000 --- a/resources/js/components/Factory/Sidebar/BlockContainer.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/BlockFooter.vue b/resources/js/components/Factory/Sidebar/BlockFooter.vue deleted file mode 100644 index 6b3e8f24..00000000 --- a/resources/js/components/Factory/Sidebar/BlockFooter.vue +++ /dev/null @@ -1,89 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/BlockInteraction.test.ts b/resources/js/components/Factory/Sidebar/BlockInteraction.test.ts deleted file mode 100644 index 3f6a1229..00000000 --- a/resources/js/components/Factory/Sidebar/BlockInteraction.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { mount } from "@vue/test-utils"; -import { describe, expect, it } from "vitest"; -import BlockInteraction from "./BlockInteraction.vue"; - -describe("BlockInteraction", () => { - it.each(["range", "file"])( - "mounts a new %s interaction whose options are still null", - (type) => { - const interaction = { - type, - label: null, - options: null, - } as unknown as FormBlockInteractionModel; - - expect(() => - mount(BlockInteraction, { props: { interaction } }), - ).not.toThrow(); - }, - ); -}); diff --git a/resources/js/components/Factory/Sidebar/BlockInteraction.vue b/resources/js/components/Factory/Sidebar/BlockInteraction.vue deleted file mode 100644 index cc2f3242..00000000 --- a/resources/js/components/Factory/Sidebar/BlockInteraction.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue b/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue deleted file mode 100644 index 69c3738f..00000000 --- a/resources/js/components/Factory/Sidebar/BlockLogicVisualizer.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/ConsentBlockMessage.vue b/resources/js/components/Factory/Sidebar/ConsentBlockMessage.vue deleted file mode 100644 index c9f795d1..00000000 --- a/resources/js/components/Factory/Sidebar/ConsentBlockMessage.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/DefaultBlockMessage.vue b/resources/js/components/Factory/Sidebar/DefaultBlockMessage.vue deleted file mode 100644 index a6c98afc..00000000 --- a/resources/js/components/Factory/Sidebar/DefaultBlockMessage.vue +++ /dev/null @@ -1,14 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/Group.vue b/resources/js/components/Factory/Sidebar/Group.vue deleted file mode 100644 index 13c152bf..00000000 --- a/resources/js/components/Factory/Sidebar/Group.vue +++ /dev/null @@ -1,127 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/InsertAfterButton.vue b/resources/js/components/Factory/Sidebar/InsertAfterButton.vue deleted file mode 100644 index 7dd11cb4..00000000 --- a/resources/js/components/Factory/Sidebar/InsertAfterButton.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Sidebar/Storyboard.vue b/resources/js/components/Factory/Sidebar/Storyboard.vue deleted file mode 100644 index dcf43ea1..00000000 --- a/resources/js/components/Factory/Sidebar/Storyboard.vue +++ /dev/null @@ -1,138 +0,0 @@ - - - diff --git a/resources/js/components/Factory/sanitize.test.ts b/resources/js/components/Factory/sanitize.test.ts index e2c6d6e6..b0d98de9 100644 --- a/resources/js/components/Factory/sanitize.test.ts +++ b/resources/js/components/Factory/sanitize.test.ts @@ -1,34 +1,41 @@ import { mount } from "@vue/test-utils"; import { describe, expect, it } from "vitest"; -import DefaultBlockMessage from "./Sidebar/DefaultBlockMessage.vue"; +import DocumentQuestion from "./Document/DocumentQuestion.vue"; import BlockSubmissionItem from "./Submissions/BlockSubmissionItem.vue"; const unsafeHtml = '

Hello

'; describe("question texts in the admin", () => { - it.each([ - [ - "builder sidebar", - () => - mount(DefaultBlockMessage, { props: { content: unsafeHtml } }), - ], - [ - "results", - () => - mount(BlockSubmissionItem, { - props: { - block: { - message: unsafeHtml, - session_count: 1, - interactions: [], - } as Partial as FormBlockModel, - }, - }), - ], - ])("%s renders without event handlers", (_, mountText) => { - const wrapper = mountText(); + it("results render without event handlers", () => { + const wrapper = mount(BlockSubmissionItem, { + props: { + block: { + message: unsafeHtml, + session_count: 1, + interactions: [], + } as Partial as FormBlockModel, + }, + }); expect(wrapper.text()).toContain("Hello"); expect(wrapper.find("img").attributes()).not.toHaveProperty("onerror"); }); + + it("the editor's document shows the text as plain text", () => { + const wrapper = mount(DocumentQuestion, { + props: { + block: { + id: 1, + uuid: "a", + type: "radio", + message: unsafeHtml, + interactions: [], + } as Partial as FormBlockModel, + number: 1, + }, + }); + + expect(wrapper.text()).toContain("Hello"); + expect(wrapper.find("img").exists()).toBe(false); + }); }); diff --git a/resources/js/stores/form.ts b/resources/js/stores/form.ts index 59053ec3..8cc39946 100644 --- a/resources/js/stores/form.ts +++ b/resources/js/stores/form.ts @@ -238,6 +238,8 @@ export const useForm = defineStore("form", { async createFormBlock( insertAfter: FormBlockModel | null = null, type: FormBlockType | null = null, + // for an empty group: there's no block to insert after + parentBlock: string | null = null, ) { if (!this.form) { return; @@ -260,6 +262,12 @@ export const useForm = defineStore("form", { this.blocks.splice(index + 1, 0, newBlock); + this.saveBlockSequence(); + } else if (parentBlock) { + newBlock.parent_block = parentBlock; + + this.blocks.push(newBlock); + this.saveBlockSequence(); } else { this.blocks.push(newBlock); diff --git a/resources/js/utils/useActiveCard.ts b/resources/js/utils/useActiveCard.ts deleted file mode 100644 index 713a1ca9..00000000 --- a/resources/js/utils/useActiveCard.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { computed, ComputedRef, Ref } from "vue"; - -export function useActiveCard(isActive: Ref): { - cardStyle: ComputedRef; -} { - const cardStyle = computed(() => { - if (isActive.value === true) { - return "border-2 border-grey-500 bg-white"; - } else { - return "border-2 border-grey-200 bg-white"; - } - }); - - return { cardStyle }; -} From ef0663e288c1c33a3d6826abbdae12c3fa5e9e64 Mon Sep 17 00:00:00 2001 From: Philipp Reinking Date: Tue, 13 Oct 2026 01:04:45 +0200 Subject: [PATCH 002/153] feat: put grip and delete inside each choice row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete and the drag grip showed only on hover, 96 px left of the row and outside the tab order. Now they sit at the end of the row, always visible; delete is a named button ("Delete choice “Yes”"). Co-Authored-By: Claude Opus 5.5 --- .../Factory/Main/ChoiceRowActions.vue | 33 +++++++++++++++++++ .../Factory/Main/InteractionHoverActions.vue | 24 -------------- .../Main/Interactions/ClickInteraction.vue | 14 ++++---- .../Main/Interactions/ConsentInteraction.vue | 8 +++-- 4 files changed, 47 insertions(+), 32 deletions(-) create mode 100644 resources/js/components/Factory/Main/ChoiceRowActions.vue delete mode 100644 resources/js/components/Factory/Main/InteractionHoverActions.vue diff --git a/resources/js/components/Factory/Main/ChoiceRowActions.vue b/resources/js/components/Factory/Main/ChoiceRowActions.vue new file mode 100644 index 00000000..58b546a6 --- /dev/null +++ b/resources/js/components/Factory/Main/ChoiceRowActions.vue @@ -0,0 +1,33 @@ + + + diff --git a/resources/js/components/Factory/Main/InteractionHoverActions.vue b/resources/js/components/Factory/Main/InteractionHoverActions.vue deleted file mode 100644 index cde6c160..00000000 --- a/resources/js/components/Factory/Main/InteractionHoverActions.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/resources/js/components/Factory/Main/Interactions/ClickInteraction.vue b/resources/js/components/Factory/Main/Interactions/ClickInteraction.vue index ba678267..2a6c02ff 100644 --- a/resources/js/components/Factory/Main/Interactions/ClickInteraction.vue +++ b/resources/js/components/Factory/Main/Interactions/ClickInteraction.vue @@ -1,7 +1,7 @@ diff --git a/resources/js/components/Factory/Document/FormDocument.vue b/resources/js/components/Factory/Document/FormDocument.vue index 915f6433..58ac1ce4 100644 --- a/resources/js/components/Factory/Document/FormDocument.vue +++ b/resources/js/components/Factory/Document/FormDocument.vue @@ -1,8 +1,12 @@ - + { const item = await previewItem(false); expect(text(item!)).toBe("Preview ↗"); expect(item?.getAttribute("aria-label")).toBe("Preview (opens in a new tab)"); - expect(item?.getAttribute("href")).toBe(`${location.origin}/forms.show`); + // in preview mode: no answers are stored + expect(item?.getAttribute("href")).toBe(`${location.origin}/forms.show?preview=1`); expect(item?.getAttribute("target")).toBe("_blank"); // from 1024 px it's in the bar expect(await previewItem(true)).toBeUndefined(); diff --git a/resources/js/components/Factory/TopBar/FormTopBar.vue b/resources/js/components/Factory/TopBar/FormTopBar.vue index 0a5f686f..76a0ac0e 100644 --- a/resources/js/components/Factory/TopBar/FormTopBar.vue +++ b/resources/js/components/Factory/TopBar/FormTopBar.vue @@ -55,10 +55,11 @@ > - +