Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
a3a6f5b
fix: use plain words in the answer field, rating, date and file settings
PhilReinking Oct 13, 2026
3d5ca41
fix: say choice and consent in the choice and consent settings
PhilReinking Oct 13, 2026
0e9e6a9
fix: name the settings by answer type and say where the short name shows
PhilReinking Oct 13, 2026
0a5b7a1
fix: show every switch in the editor as on or off
PhilReinking Oct 13, 2026
3170da7
fix: use plain words in the text editor's toolbar, counter and prompts
PhilReinking Oct 13, 2026
3e1e426
fix: name new rules Rule 1 and give the group name an example
PhilReinking Oct 13, 2026
50015c0
docs: use the editor's new setting names in the help pages
PhilReinking Oct 13, 2026
26b6454
Merge remote-tracking branch 'origin/stack/bits-274-phase-2' into fea…
PhilReinking Oct 13, 2026
f77efdb
docs: add the editor wording change to the changelog
PhilReinking Oct 13, 2026
b698273
fix: don't say emails use the short name
PhilReinking Oct 13, 2026
4ee7e54
fix: tie "None ticked: all types allowed." to the file type boxes
PhilReinking Oct 13, 2026
2e16cb7
fix: use plain words for the text editor's default placeholder
PhilReinking Oct 13, 2026
84d0bd9
fix: drop the settings heading where a type has no settings of its own
PhilReinking Oct 13, 2026
4798dbf
fix: say "a deleted question" in a rule's sentence
PhilReinking Oct 13, 2026
0af912b
fix: use short example placeholders in the long text and number settings
PhilReinking Oct 13, 2026
b294005
fix: show an example, not "No limit", as the max characters placeholder
PhilReinking Oct 13, 2026
c6354e6
fix: start the Consent and Text only settings at the panel top
PhilReinking Oct 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Lines marked **Upgrade step** need you to act after updating.
- The form editor shows your whole form as one column. Each question shows its number, answer type, text, and if it is required, has rules or is hidden. The question you work on opens right there, also on a phone, where you couldn't edit questions before. Hiding a question, random order and custom answers are now under the question's Settings. An outline next to the form jumps to any question, and on a phone a question's Settings open from the bottom of the screen. Move a question with Alt+Up/Down, with Move up and Move down in its menu, or by dragging. Duplicate in a question's menu puts a copy right below it. (#268, #272, #275, #277)
- Deleting a question, a group, an answer choice, a consent policy or a logic rule in the form editor now asks first in the app's own dialog. It names the question, how many answers will be deleted with it, and the questions whose rules will stop working. A choice nobody picked, or a policy nobody agreed to, is still deleted at once. (#269)
- Each rule now shows as a sentence under its question, and a group says when it's hidden. Edit changes a rule right there, and for choices, ratings and scales you pick the answer instead of typing it. A rule whose question was deleted shows in red and can't be saved until you fix it. (#274)
- The form editor uses plain words: a question's settings are headed by its answer type, like Choices or Rating, "Identifier" is now "Short name", and every switch shows on or off. Settings name what they do, like "Lowest value", "Shuffle choices" and "None ticked: all types allowed." on file uploads. (#279)

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions docs/embedding-forms.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ https://app.getinput.co/form-uuid?iframe=1&hideTitle=1&alignLeft=1

## Prefill Questions

You can fill in answers with URL parameters. The parameter name is the question's Identifier (open the question, then "More Settings"). For example, this fills the question with the Identifier `email`:
You can fill in answers with URL parameters. The parameter name is the question's short name (open the question, then **Settings**, then **Short name**). For example, this fills the question with the short name `email`:

```
https://app.getinput.co/form-uuid?email=ada@example.com
```

- Works for short text, long text, email, number, phone and link questions. Parameters for other question types or unknown Identifiers are ignored.
- Works for short text, long text, email, number, phone and link questions. Parameters for other question types or unknown short names are ignored.
- The question still shows, so the visitor can check and change the answer. A question skipped by a jump doesn't send its prefilled answer.
- The value shows as plain text. Encode special characters: `%2B` for `+`, `%20` for a space.
- Number questions take digits with a dot as decimal separator, like `price=12.5`, rounded to the question's decimal places. Anything else is ignored.
Expand Down
2 changes: 1 addition & 1 deletion docs/input-types/consent.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The Consent input type is designed specifically for gathering agreement from use
1. Choose **Consent** as the input type
2. Enter a clear message explaining what the user is consenting to
3. Configure the consent option with a concise label
4. Toggle "Opt-In Required" if the consent is mandatory to proceed
4. Turn on "Must be ticked" if people must agree to go on

::: tip Best Practice
< Keep consent messages clear and specific. Explain exactly what users are agreeing to, and include links to relevant policies when appropriate.
Expand Down
6 changes: 3 additions & 3 deletions docs/input-types/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ The Date input type allows users to select dates from a calendar interface, maki
1. Choose **Date** as the input type
2. Enter the question or prompt asking for a date
3. Configure the date restrictions (optional):
- **Minimum Date**: Earliest date users can select
- **Maximum Date**: Latest date users can select
- **No Past Dates**: Toggle to prevent selection of dates before today
- **Min date**: Earliest date users can select
- **Max date**: Latest date users can select
- **No dates in the past**: Turn on to prevent selection of dates before today

::: tip Best Practice
< Always specify what kind of date you're asking for (appointment date, birth date, event date, etc.) and the expected format in your prompt.
Expand Down
6 changes: 3 additions & 3 deletions docs/input-types/file-upload.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ The File upload input type allows users to attach files to their form responses.
1. Choose **File upload** as the input type
2. Enter instructions for what files users should upload
3. Configure the upload settings:
- **Maximum Files**: Set how many files users can upload
- **Maximum File Size**: Limit file size (in MB)
- **Allowed File Types**: Choose which file formats are accepted
- **Most files**: How many files users can upload (1 to 10)
- **Largest file (MB)**: Up to 8 MB per file
- **File types**: Choose which file formats are accepted. None ticked: all types allowed

::: tip Best Practice
< Be specific about what files you're looking for and any requirements (format, size, resolution, etc.) to avoid confusion and unsuccessful uploads.
Expand Down
4 changes: 2 additions & 2 deletions docs/input-types/long-text.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ The Long text input type provides a multi-line text area for collecting detailed
1. Select **Long text** as the input type
2. Enter the question or prompt
3. Configure the text area options:
- **Rows**: Number of visible text rows (1-10, default: 5)
- **Maximum Characters**: Limit on response length (default: 500)
- **Height in lines**: How many lines the field shows (1 to 10, default: 5)
- **Max characters**: Limit on response length (default: 500)
- **Placeholder**: Hint text shown when the field is empty
4. Toggle the "Required" option if necessary

Expand Down
2 changes: 1 addition & 1 deletion docs/input-types/multiplechoice.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This input type allows users to select one option from a list of choices, perfec
- **Single Selection**: Users can select exactly one option
- **Visual Clarity**: Clear indication of which option is selected
- **Option Ordering**: Arrange options in a meaningful sequence
- **Randomization**: Option to randomize choice order to reduce bias (if available)
- **Shuffle choices**: Show the choices in a random order to reduce bias

## Example Uses:

Expand Down
4 changes: 2 additions & 2 deletions docs/input-types/number.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ The Number input type is specifically designed for collecting numerical data wit
1. Choose **Number** as the input type
2. Enter the question or prompt
3. Configure the number options:
- **Decimal Places**: How many decimal digits to allow (0-10)
- **Symbol**: Optional character(s) to display before the number (e.g., $, €, %)
- **Decimal places**: How many decimal digits to allow (0-10). Leave empty for whole numbers only
- **Symbol**: Shown next to the number, e.g. € or kg
- **Placeholder**: Hint text to show when the field is empty
4. Toggle the "Required" option if necessary

Expand Down
8 changes: 4 additions & 4 deletions docs/input-types/rating.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ The Rating input type allows users to provide feedback on a visual scale using i
1. Choose **Rating** as the input type
2. Enter the prompt for what's being rated
3. Configure the rating options:
- **Min Rating**: Starting point for the scale (default: 1)
- **Max Rating**: Maximum value on the scale (default: 5)
- **Left Label**: Optional text at the start of the scale (e.g., "Poor")
- **Right Label**: Optional text at the end of the scale (e.g., "Excellent")
- **Lowest value**: Starting point for the scale (default: 1)
- **Highest value**: Maximum value on the scale (default: 5)
- **Label for lowest**: Optional text at the start of the scale (e.g., "Poor")
- **Label for highest**: Optional text at the end of the scale (e.g., "Excellent")
- **Icon**: Choose from stars, hearts, trophies, and other symbols
- **Color**: Customize the color of the rating icons
4. Toggle the "Required" option if necessary
Expand Down
8 changes: 4 additions & 4 deletions docs/input-types/scale.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ The Scale input type presents users with a numerical range from which they can s
1. Select **Scale** as the input type
2. Enter the question or prompt
3. Configure the scale options:
- **Min Rating**: Starting number for the scale (default: 1)
- **Max Rating**: Ending number for the scale (default: 5)
- **Left Label**: Text description for the low end of the scale (e.g., "Strongly Disagree")
- **Right Label**: Text description for the high end of the scale (e.g., "Strongly Agree")
- **Lowest value**: Starting number for the scale (default: 1)
- **Highest value**: Ending number for the scale (default: 5)
- **Label for lowest**: Text description for the low end of the scale (e.g., "Strongly Disagree")
- **Label for highest**: Text description for the high end of the scale (e.g., "Strongly Agree")
4. Toggle the "Required" option if necessary

## Features:
Expand Down
2 changes: 1 addition & 1 deletion docs/managing-submissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The Table View displays each individual submission in a tabular format:

The Summary View provides an aggregated analysis of your submissions:

- For multiple choice questions: shows response distributions with visual graphs
- For single choice and checkbox questions: shows response distributions with visual graphs
- For text inputs: displays common responses
- For numerical inputs: shows average values and ranges
- For rating scales: presents average ratings with visual indicators
Expand Down
4 changes: 2 additions & 2 deletions docs/workbench/workbench.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Each question shows:

- Its number and an icon for its answer type
- Its text, on up to two lines
- A line below with the answer type, the number of choices, **Required**, the number of rules, **Hidden**, and its identifier if you gave it one
- A line below with the answer type, the number of choices, **Required**, the number of rules, **Hidden**, and its short name if you gave it one

Groups show their name with their questions inside. An empty group says how to add a question to it.

Expand All @@ -26,7 +26,7 @@ Click a question, or move to it with Tab and press Enter, to open it in place. T
2. **Choices** - For single choice and checkboxes. Each row has a grip to drag it and a delete button. Alt+Up and Alt+Down move a choice
3. **Answer type** - Change what kind of answer the question takes
4. **Required** - Whether people must answer it
5. **Settings** - The settings of this answer type, the identifier and **Hide this question**. On a phone they open as a sheet from the bottom
5. **Settings** - The settings of this answer type under its own heading (for example **Choices** or **Rating**), then **Short name** and **Hide this question**. On a phone they open as a sheet from the bottom
6. **Rules** - Logic rules for this question, see [Conditional Logic](./conditional-logic.md)
7. **Menu (…)** - Duplicate, Add question below, Move up, Move down, Copy question ID and Delete

Expand Down
4 changes: 2 additions & 2 deletions resources/js/components/EmptyState.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
>
<div :class="isLoading ? 'opacity-0' : ''">
<h3 class="font-heading font-medium text-grey-900">{{ title }}</h3>
<small class="block font-sans text-sm">
<small v-if="description" class="block font-sans text-sm">
{{ description }}
</small>
</div>
Expand All @@ -22,7 +22,7 @@ import { D9Spinner } from "@deck9/ui";

defineProps<{
title: string;
description: string;
description?: string;
isLoading?: boolean;
}>();
</script>
2 changes: 1 addition & 1 deletion resources/js/components/Factory/Document/DocumentGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
:id="`${id}-name`"
v-model="name"
type="text"
placeholder="Group"
placeholder="e.g. About you"
title="Use a group to show or hide several questions with one rule."
class="h-11 min-w-0 flex-1 rounded-md border-0 bg-transparent px-2 text-base font-semibold lg:h-9 lg:text-sm text-grey-700 placeholder:text-grey-600 hover:bg-grey-100 focus:bg-white focus:ring-2 focus:ring-blue-500"
/>
Expand Down
2 changes: 0 additions & 2 deletions resources/js/components/Factory/Document/EndScreenBlock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@
id="end-screen-button"
v-model="draft.show_cta_link"
label="Button"
onLabel="Yes"
offLabel="No"
/>
<Link
:href="settingsLink"
Expand Down
2 changes: 0 additions & 2 deletions resources/js/components/Factory/Document/QuestionCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@
:id="`${id}-required`"
v-model="required"
label="Required"
onLabel="Yes"
offLabel="No"
/>
</div>

Expand Down
45 changes: 45 additions & 0 deletions resources/js/components/Factory/Document/QuestionSettings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, expect, it } from "vitest";
import { shallowMount } from "@vue/test-utils";
import QuestionSettings from "./QuestionSettings.vue";

const heading = (type: string, interactionType?: FormBlockInteractionType) =>
shallowMount(QuestionSettings, {
props: {
id: "settings",
block: {
uuid: "q1",
type,
interactions: [],
} as unknown as FormBlockModel,
interactionType,
},
}).find("h3");

describe("the settings heading", () => {
it.each([
["radio", "button", "Choices"],
["input-short", "input", "Answer field"],
["input-long", "textarea", "Answer field"],
["rating", "range", "Rating"],
["scale", "range", "Scale"],
["date", "date", "Date"],
["input-file", "file", "File upload"],
] as const)(
"names a %s question's settings %s → %s",
(type, interaction, text) => {
expect(heading(type, interaction).text()).toBe(text);
expect(heading(type, interaction).attributes("hidden")).toBe(
undefined,
);
},
);

// their panel holds only Short name and Hide this question
it.each([
["consent", "consent"],
["none", undefined],
] as const)("shows no heading for a %s question", (type, interaction) => {
expect(heading(type, interaction).text()).toBe("Settings");
expect(heading(type, interaction).attributes("hidden")).toBe("");
});
});
29 changes: 22 additions & 7 deletions resources/js/components/Factory/Document/QuestionSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
:id="`${id}-title`"
class="text-xs font-semibold text-grey-600"
:class="sheet && 'sr-only'"
:hidden="!heading"
>
Settings
{{ heading || "Settings" }}
</h3>

<ConfigureInput v-if="interactionType === 'input'" />
Expand All @@ -33,11 +34,10 @@
<label
:for="`${id}-identifier`"
class="block text-sm font-medium text-grey-900"
>Identifier</label
>Short name</label
>
<p :id="`${id}-identifier-help`" class="mb-1 text-xs text-grey-600">
This name is used when submitting your form through webhooks and in the
export.
Used in prefill links, webhooks and the submissions table.
</p>
<D9Input
:id="`${id}-identifier`"
Expand All @@ -60,15 +60,13 @@
:id="`${id}-hidden`"
v-model="hidden"
label="Hide this question"
onLabel="Yes"
offLabel="No"
/>
</div>
</div>
</template>

<script setup lang="ts">
import { ref, watch } from "vue";
import { computed, ref, watch } from "vue";
import { D9Input, D9Switch } from "@deck9/ui";
import { useWorkbench } from "@/stores";
import useActiveInteractions from "@/components/Factory/Shared/useActiveInteractions";
Expand All @@ -91,6 +89,23 @@ const props = defineProps<{
const workbench = useWorkbench();
const { editableInteractions } = useActiveInteractions(props.block);

// named by answer type; Consent and Text only have no settings of their own,
// so their heading is hidden: it still names the group, and space-y skips it
const headings: Partial<Record<FormBlockInteractionType, string>> = {
button: "Choices",
input: "Answer field",
textarea: "Answer field",
date: "Date",
file: "File upload",
};
const heading = computed(() => {
if (props.interactionType === "range") {
return props.block.type === "scale" ? "Scale" : "Rating";
}

return props.interactionType && headings[props.interactionType];
});

const title = ref(props.block.title ?? "");
const hidden = ref(props.block.is_disabled ?? false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ describe("a rule under its question", () => {
const broken = wrapper.findAll(".text-red-700");

expect(broken).toHaveLength(2);
expect(broken[0].text()).toContain("Deleted question");
expect(broken[0].text()).toContain("a deleted question");
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<span
class="inline-flex items-center gap-1 rounded bg-red-50 px-1.5 font-medium text-red-700 ring-1 ring-inset ring-red-200"
>
<D9Icon name="triangle-exclamation" aria-hidden="true" />Deleted question
<D9Icon name="triangle-exclamation" aria-hidden="true" />a deleted question
</span>
</template>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function addRule(block: FormBlockModel) {
...logics,
{
form_block_id: block.id,
name: `Rule #${logics.length + 1}`,
name: `Rule ${logics.length + 1}`,
action: isGroup ? "hide" : "goto",
action_payload: null,
evaluate: isGroup ? "before" : "after",
Expand Down
3 changes: 1 addition & 2 deletions resources/js/components/Factory/Main/ConfigureClicks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
<div>
<EmptyState
v-if="editableInteractions?.length === 0"
title="Nothing here yet."
description="Add your first choice with the button below."
title="No choices yet."
/>

<Container
Expand Down
5 changes: 2 additions & 3 deletions resources/js/components/Factory/Main/ConfigureConsents.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
<div>
<EmptyState
v-if="workbench.currentInteractions?.length === 0"
title="Nothing here yet."
description="Add your first policy with the button below."
title="No consents yet."
/>

<Container
Expand Down Expand Up @@ -34,7 +33,7 @@
@click="createConsentPolicy"
>
<D9Icon name="plus" aria-hidden="true" />
Add policy
Add consent
</button>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions resources/js/components/Factory/Main/ConfigureDate.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<template>
<div>
<div class="mb-4">
<D9Label id="date-min" label="Min Date" />
<D9Label id="date-min" label="Min date" />
<D9Input id="date-min" type="date" block v-model="minDate" />
</div>
<div class="mb-4">
<D9Label id="date-max" label="Max Date" />
<D9Label id="date-max" label="Max date" />
<D9Input id="date-max" type="date" block v-model="maxDate" />
</div>
<div class="mb-4 flex items-center justify-between">
<D9Label id="no-past-dates" label="Do not allow past dates" />
<D9Label id="no-past-dates" label="No dates in the past" />
<D9Switch id="no-past-dates" label="" v-model="noPastDates" />
</div>
</div>
Expand Down
Loading