Question Management & Annotation Form: UI Specification¶
Detailed UI and interaction specification for the Question Management (QM) redesign and connected Annotation Form updates. Covers information architecture, component specifications, interaction patterns, state management, and accessibility. Implementation tracked via Epic #2488.
Table of Contents¶
- Design Decisions
- Information Architecture
- Design View
- Assign View
- Preview View
- Publish Wizard
- Annotation Form Updates
- Versioning UX
- Accessibility
- State Management & Performance
- Research References
1. Design Decisions¶
Agreed design decisions from the evaluation and discussion sessions. These are the foundation for the specification.
DD-01: Project Navigation Integration¶
Decision: Design, Assign, and Preview become sub-items under a "Questions" section in the project sidebar navigation, rather than tabs within the QM content area.
Rationale: - Eliminates nested tabs (previously: QM tabs > category tabs) - The horizontal bar is reserved exclusively for category navigation - Categories are always tabs at the top across all three views -- consistent with the annotation form's visual language - Design, Assign, Preview are distinct workflows that happen at different times, not parallel views of the same thing
Structure:
Project Sidebar Nav Content Area
--------------------- ----------------------------------
Dashboard [Study] [DMI] [Treatment] [OA] [Cohort] [Exp]
Studies ... view-specific content ...
Screening
Data Extraction
v Questions
Design <-- active
Assign
Preview
Stages
Members
Settings
Behaviour: Selected category persists when switching between Design/Assign/Preview via a route parameter or shared state.
DD-02: Workspace Layout -- WYSIWYG Tree + Properties Panel¶
Decision: The Design view uses a split-panel layout: a compact WYSIWYG question flow on the left, and a properties/edit panel on the right.
Rationale: - SyRF questions have ~10+ editable fields (text, description, type, control type, options, conditional settings, required, multiple, answer array, default checkbox status, etc.). Expanding all fields inline bloats tree nodes and pushes siblings out of view. - A properties panel keeps the tree compact and navigable at all times. - Clicking through questions to compare them is fast -- the tree doesn't change shape, only the panel updates. - Drag-and-drop works on compact nodes without awkwardness. - Version history and assignment info can live in the panel without bloating the tree. - This is the SurveyJS Creator / Figma / VS Code pattern -- familiar to users of any design tool.
The tree IS the lightweight preview: The compact hybrid view in the tree shows question text, type badge, option count, required indicator. It emulates the annotation form's question flow.
DD-03: Category Navigation via Horizontal Tabs¶
Decision: Categories (Study, DMI, Treatment, OA, Cohort, Experiment) are displayed as horizontal tabs spanning the full content width, above the view-specific content. This applies to all three views (Design, Assign, Preview).
Rationale: - Horizontal tabs are the visual language already established by the annotation form -- all SyRF users are familiar with this pattern. - Horizontal tabs use negligible vertical space (~40px) compared to a vertical MatNavList (~336px for 7 items). - Avoids the vertical space problem that would arise from putting category nav in a sidebar.
Component options (any of these work):
- mat-tab-nav-bar (already used in codebase -- lowest change)
- MatChipListbox horizontal (more compact, clear selected state)
- MatButtonToggleGroup horizontal (clean selection semantics)
DD-04: Assign View -- Single Tree with Filter Toggle¶
Decision: The Assign view uses a single question tree with checkboxes per stage (one stage at a time via dropdown), replacing the dual-tree approach.
Rationale: - Single mental model: check to assign, uncheck to unassign - No "assignment mode" vs "unassignment mode" - System questions show a dash (auto-included, not user-controllable) - A "Show" filter toggle (All / On stage / Not on stage) provides the stage-specific tree view that the dual-tree offered
DD-05: Publishing Spectrum (Three Zones)¶
Decision: Question publishing follows a three-zone spectrum rather than a binary locked/unlocked model.
| Zone | State | Constraints | Reversible? |
|---|---|---|---|
| Drafting | DraftAQs on project | Everything mutable | N/A |
| Published, no annotations | AQs exist, stage active, no submissions yet | Structure frozen, content versionable | Use "Replace with new version" to create new editable drafts |
| Published, with annotations | Annotations reference specific AQVersions | Content versionable only (new version) | Use "Replace with new version"; handling decisions made at publish time |
Rationale: Matches REDCap's Development/Production model. The ceremony's intensity matches the stakes. Accidental publishing is recoverable if caught before annotators start working.
DD-06: Annotation Form -- Keep Tabs, Add Collapsible Unit Tiles¶
Decision: The annotation form keeps category tabs (familiar, unchanged) and adds collapsible unit tiles within categories that have units (DMI, Treatment, OA, Cohort, Experiment).
Rationale: - Category tabs are familiar to all SyRF users and support the focused, sequential data entry workflow. - Collapsible unit tiles (chip-like pills with status indicators) are new functionality -- units currently render all questions inline with no collapse/expand. - Tiles give quick navigation, progress visibility, and performance improvement (collapsed units don't render form fields). - Based on SurveyJS Dynamic Panel pattern.
DD-07: Completion Indicators -- Three-State, No Fixed Denominator¶
Decision: Unit completion uses three states (complete / in-progress / not started) without showing absolute counts like "⅗".
Rationale: The number of visible questions is dynamic due to conditional question logic. A parent answer can reveal or hide child questions, changing the total. A three-state indicator adapts automatically without confusing the user with changing numbers.
- Complete (checkmark): All currently-visible questions answered
- In progress (half-filled): Some answered, some remaining
- Not started (empty): Nothing answered
Alternative: A progress ring (thin donut chart) that fills proportionally to visible-question completion. No numbers, just visual proportion.
DD-08: Option Description Field -- Ignore¶
Decision: The Description field on question options is a data artifact that is never displayed. The new UI should only expose Value (what annotators see and what gets stored).
Rationale: Confirmed via code analysis -- Description is defined in the data model but never rendered in any annotation form component, question editor, or data export.
2. Information Architecture¶
Navigation Hierarchy¶
Project
|-- Dashboard
|-- Studies
|-- Screening
|-- Data Extraction
|-- Questions <-- expandable section
| |-- Design <-- WYSIWYG tree + properties panel
| |-- Assign <-- single tree, checkboxes, filter toggle
| |-- Preview <-- interactive annotation form simulation
|-- Stages
|-- Members
|-- Settings
Content Area Structure¶
All three Question views share a common horizontal category bar:
+--------------------------------------------------------------+
| [Study] [DMI] [Treatment] [OA] [Cohort] [Experiment] | <-- category tabs (shared)
+--------------------------------------------------------------+
| |
| View-specific content (Design / Assign / Preview) |
| |
+--------------------------------------------------------------+
Category Navigation Behaviour¶
- Selecting a category filters the view to show only questions in that category
- Selected category persists across Design/Assign/Preview navigation changes
- Category badge shows question count:
Treatment (4) - Category tab appearance matches the annotation form's category tabs for visual consistency
URL Structure¶
/project/:projectId/admin/questions/design?category=treatment&q=<questionId>
/project/:projectId/admin/questions/assign?category=treatment&stage=:stageId&q=<questionId>
/project/:projectId/admin/questions/preview?category=treatment&stage=:stageId
Category and stage selections are query parameters, not route segments, so they persist naturally across view transitions.
Selected question: ?q=<questionId> is appended as a query parameter for deep linking to a specific question. On load, the tree auto-expands ancestors of the selected question and scrolls it into view.
URL update strategy:
- Category and view changes use
pushState(create browser history entries -- intentional navigation) - Question selection uses
replaceState(no history pollution -- UI refinement, not navigation) queryParamsHandling: 'merge'preserves existing params when updating a single param- Stale links (deleted question) gracefully degrade to showing the category with no selection
What is NOT encoded in the URL: Panel width (stored in localStorage), expansion state (component state, auto-derived from ?q), scroll position (auto-derived from ?q).
3. Design View¶
Framing Line¶
A persistent, subtle line at the top of the Design workspace:
Changes here are drafts — annotators won't see them until you publish to a stage.
This establishes the sandbox mental model. The admin has permission to experiment freely because nothing in the Design view is live.
Layout¶
Split-panel workspace: WYSIWYG question tree (left) + properties panel (right).
+--------------------------------------------------------------+
| [Study] [DMI] [Treatment <-sel] [OA] [Cohort] [Experiment] |
+-----------------------------+--------------------------------+
| | |
| QUESTION FLOW | PROPERTIES |
| (compact, hybrid view) | (edit form for selected Q) |
| | |
| +------------------------+ | Question Text |
| | Drug Name | | [Drug Name ] |
| | TextBox . Required | | |
| +------------------------+ | Description |
| +========================+ | [ ] |
| || Dose <- sel || | |
| || TextBox . Required || | Type: [String v] |
| || "mg/kg" || | Control: [TextBox v] |
| +========================+ | [x] Required |
| +------------------------+ | [ ] Multiple answers |
| | Route | | |
| | Dropdown . Optional | | Conditional display: |
| | Oral, IV, IP, SC | | Parent: [Treatment Ctrl v] |
| +------------------------+ | Show when: [Non-control v] |
| | |
| [+ Add Question] | All changes saved |
| | |
+-----------------------------+--------------------------------+
Left Panel -- Question Flow (WYSIWYG Tree)¶
The left panel displays questions in their natural hierarchy using a compact "hybrid" view. Each question node shows:
- Expand/collapse chevron (LEFT side, before all other content -- per GitHub Primer, Carbon, PatternFly conventions). Leaf nodes get an invisible spacer for alignment.
- Drag handle for reordering
- Control type icon using existing SyRF Material Icons:
short_text(Input Box),arrow_drop_down_circle(Dropdown),check_box(Checkbox),checklist(Checklist),spellcheck(Autocomplete),radio_button_checked(Radio) - Question text -- full text, wrapping to multiple lines (NO truncation). Row uses
align-items: flex-startso icons align to the first line. - Required indicator (small red dot)
- Status indicator:
edit_noteDraft (never published),task_altPublished (live, clean), orpublished_with_changesPublished with changes (has unpublished edits). NO version numbers on nodes (see PDD-17 for terminology). - Warning icon (amber triangle) if cross-question validation issues exist
- Annotation count indicator for questions with answers
- Selection highlight (border change) for the currently-selected question
Tree connectors: L-shaped branch lines showing parent-child relationships. Vertical lines connect siblings. Last child has no trailing vertical line. Same pattern as IDE file explorers.
Focus mode: When the tree exceeds 6 levels of indentation from the current visual root, focus mode activates automatically. The tree re-roots to show a subtree, displaying only the deeply nested portion. A breadcrumb bar appears above the tree showing the full path from root to the current focus point, with clickable links at each ancestor to navigate back up. A "Show full tree" exit button restores the complete tree view.
Focus mode specifics:
- Trigger: Automatic when a question at depth 6+ is selected or expanded. Can also be triggered manually by right-clicking a node and selecting "Focus on subtree".
- Breadcrumb bar: Fixed above the tree panel. Shows: tree icon > ancestor 1 > ancestor 2 > ... > current root (non-clickable). Each ancestor is a clickable link that re-focuses at that level.
- Exit: "Show full tree" link at the right of the breadcrumb bar, or clicking the root-most breadcrumb.
- Indentation cap: The tree never visually exceeds 6 levels of indentation regardless of actual depth, preventing horizontal overflow on narrow screens.
- Persistence: Focus state is preserved when switching between Design/Assign/Preview views within the same category.
- Keyboard:
Escapeexits focus mode when the tree panel has focus.
Edit mode toggle: Admin can switch between Side Panel mode (properties on the right) and Inline Expand mode (properties expand below the node). In inline mode, each node has a separate pencil icon for opening properties -- distinct from the tree chevron.
Tree structure: Matches the annotation form's question hierarchy. System questions appear as non-editable nodes (greyed out, no drag handle). Custom questions appear as interactive nodes.
Interactions on the left panel:
| Action | Trigger | Result |
|---|---|---|
| Select question | Click question node | Properties panel updates with selected question's data |
| Expand/collapse | Click chevron | Show/hide child questions |
| Reorder | Drag via handle | Reposition within same parent (sibling constraint) |
| Add question | Click [+ Add Question] | New question created, selected, properties panel shows empty form |
| Add child | Click [+ Add Related] on a question node (via overflow menu or hover action) | New child question created under the selected parent |
Node appearance per question state (see PDD-04 and PDD-17 for full icon specification):
| State | Icon | Colour | Visual Treatment |
|---|---|---|---|
| Draft (never published) | edit_note |
Purple | Icon in meta column. Question is fully mutable. |
| Published (clean) | task_alt |
Green | Icon in meta column. Positive confirmation that the question is live. |
| Published with changes (published with pending edits) | published_with_changes |
Amber | Icon in meta column. Publishing will create a new version. |
| Published, with annotations | task_alt + annotation count |
Green | "12 studies" count alongside published icon |
| Validation warning | warning |
Amber | Warning icon, amber row tint, persists until fixed |
| Selected | — | Primary | Highlighted background + primary-colour left border |
| System question | lock + "System" badge |
Grey | Greyed out / muted, no drag handle, read-only properties |
Right Panel -- Properties Editor¶
The properties panel displays all editable fields for the selected question. It does NOT change the tree layout -- only the panel content updates when selection changes.
Resizable panel: The side panel width is adjustable via a drag handle on its left edge. Users can click and drag to resize the panel between 280px and 60% of viewport width. The drag handle shows a subtle grip indicator on hover. Panel width preference persists for the session.
Property layout order: Fields are organised in a deliberate order that prioritises context before content:
- Conditional display (top) -- parent relationship and visibility condition
- Question content -- text and help text
- Type and control -- data type, control type, options
- Behaviour toggles -- required, multiple answers, answer array (compact 2-column grid)
- Version history (bottom)
The rationale for placing conditionality first: when editing a child question, the first thing the user needs to understand is where it appears and under what conditions. This context informs all subsequent editing decisions (e.g., whether the question text should reference the parent, whether options should match parent option values).
Form fields (signal forms with schema validation):
| Section | Field | Type | Validation | Notes |
|---|---|---|---|---|
| Conditionality | Parent question | Read-only display | -- | Shows parent name with tree icon. Reordering via drag-and-drop. |
| Conditionality | Show when | Select | Conditional | Boolean (checked/unchecked) or option matching |
| Content | Question text | Text input | Required, max 80 chars | Primary question wording |
| Content | Help text | Textarea | Optional | Guidance shown to annotators below the question |
| Type | Control type | Icon selector | Required | TextBox, Dropdown, CheckBox, Radio, Checklist, Autocomplete |
| Type | Data type | Icon selector | Required | String, Integer, Decimal, Boolean |
| Type | Options | Repeatable list | Min 1 for Dropdown, unique values | For Dropdown/CheckBox/Radio/Checklist/Autocomplete |
| Behaviour | Required | Toggle | -- | Whether answer is mandatory |
| Behaviour | Multiple answers | Toggle | -- | Allow multiple selections |
| Behaviour | Answer array | Toggle | -- | Store as array |
| Behaviour | Group as single | Toggle | -- | Group with parent (structural, frozen after publish) |
| Behaviour | Default checkbox status | Select | Conditional (CheckBox only) | Initial state |
Conditional display section: Shown at the top of properties for all questions. - Root questions: Shows a subtle info line: "Root question -- always visible. Drag under another question to make it conditional." - Child questions: Shows a highlighted conditionality card with: - Parent question name (read-only, with tree icon for visual hierarchy) - Explanatory text: "This question is shown to annotators based on the parent question's answer." - Show When selector: Boolean (checked/unchecked) or option matching, depending on parent type - Context hint about reordering via drag-and-drop
Validation error highlighting: When a question has configuration errors (indicated by the warning icon in the tree), selecting it displays: - A validation summary banner at the top of the properties panel (amber background, error icon, description of each error) - The specific field(s) causing the error are highlighted with a red/amber border and an inline error message below the field - Error messages are actionable, explaining what needs to change (e.g., "Referenced parent option 'Non-control' no longer exists -- update the Show When condition") - This makes it immediately clear which property is invalid and why, without requiring the user to inspect each field manually
Option list editing: - Each option shows only the Value field (Description field is unused -- see DD-08) - Add/remove buttons per option - Drag to reorder options - Parent filter (advanced): Per-option conditional visibility based on parent question. Accessible via an overflow menu or "Advanced" expander on each option -- not prominent by default.
Autosave status indicator (bottom of properties panel): A subtle text line showing autosave state -- "All changes saved", "Saving...", or "Offline -- changes queued". No manual Save button exists. All draft changes are autosaved (debounced). There is no manual Save action. The only deliberate user action is Publish. See publishing-versioning-ux.md for the autosave model.
Annotation count display (panel header area, published questions only): Shows "Published · 47 annotations · 12 studies" as passive fact. No verb, no imperative. The admin draws their own conclusion.
Reassuring inline note (appears when editing a published question with annotations): Styled as info (blue/grey), NOT warning (amber). Appears below the field being edited:
23 annotations reference this option. Editing here updates your draft only — existing data is unaffected until you publish.
Follows the Mailchimp/NNg structure: what's relevant, what's safe, what stays the same, when it matters.
Impact & Mapping section (auto-expands when admin edits a published question with annotations, or when editing a replacement DraftQuestion with replacesAnnotationQuestionId pointing to an AQ with annotations):
The section shows annotation counts and answer distribution, and lets the admin configure preliminary decisions that will travel to the publish wizard as pre-populated suggestions.
This question has 47 annotations across 12 studies.
Editing here updates your draft only.
When published, how should existing answers be handled?
● Keep answers as they are
Best for: wording improvements, adding help text,
or changes that don't affect how answers are interpreted.
○ Map answers to updated options
Best for: fixing a typo in an option name, merging
duplicate options, or renaming for consistency.
[Configure mapping →]
○ Ask annotators to re-answer
Best for: significant changes to question meaning,
new options that may better fit previous responses,
or when the admin needs fresh judgements.
☐ Flag this change for review — annotators who have
already answered may need to reconsider
[Change note: ________________________________]
Configuration is stored as DraftPublishDecision on AQ.draft.draftPublishDecision (for edits to existing published questions) or on the DraftQuestion.draftPublishDecision (for replacement drafts with lineage). Mutable until publish.
Action buttons (bottom of properties panel):
- Delete: Opens confirmation dialog. Cascades to children.
- Duplicate: Duplicates the question without children. Copies are always Draft with new GUIDs, regardless of the original's state.
- Duplicate with children: Duplicates the question and all its descendants. All copies are Draft with new GUIDs.
- Replace with new version: Available for all published questions. Shows annotation counts if the question has annotations. Creates new DraftQuestions (new GUIDs, full copy of content) with
replacesAnnotationQuestionIdpointing to the original AQ. All published descendants are also redrafted (published children haveparentQuestionIdpointing to the old AQ, and changingparentQuestionIdis a structural change forbidden on published AQs). Originals removed from draft question set but never deleted — annotation references remain intact.
Panel states: - No selection: Shows a prompt: "Select a question to edit its properties" or a summary of the current category (question count, assignment status). - Question selected: Shows the edit form with conditionality section at top. Changes are autosaved as the user edits (debounced). The autosave status indicator reflects the current save state. - Question with errors selected: Shows validation summary + highlighted invalid fields + edit form. Autosave still operates but validation errors are highlighted immediately. - System question selected: Shows read-only informative properties including: role description (e.g., "Unit Label", "Control/Non-control Classifier"), explanation of how the question works in the annotation form, data extraction relevance (why it's auto-assigned when extraction is enabled), and a read-only summary of key properties (control type, data type, required status, hierarchy position). Properties are displayed as text labels rather than editable form controls to reinforce that they are not configurable.
Drag-and-Drop¶
- Handle: Drag icon on the left of each question node
- Constraint: Sibling-only moves (same parent). Cross-parent moves are blocked with an explanatory message.
- Visual feedback: Dropzone dividers between siblings. Active dropzone highlighted on hover.
- Keyboard alternative: Shift+Arrow keys to move a focused question up/down within its siblings (accessibility requirement)
- Auto-expand: Hovering over a collapsed node during drag for >800ms auto-expands it
- Optimistic update: Tree reorders immediately, backend save follows. On error, tree reverts.
4. Assign View¶
Layout¶
Full-width (no split panel needed -- assignment is a bulk operation, not a per-question detail task).
+--------------------------------------------------------------+
| Stage: [Extraction v] Show: [All v] |
+--------------------------------------------------------------+
| ℹ Data extraction enabled — system questions locked. |
+--------------------------------------------------------------+
| [Study] [DMI] [Treatment <-sel] [OA] [Cohort] [Experiment] |
+--------------------------------------------------------------+
| |
| [x] 🔒 Treatment Label 🔒 |
| [x] ☑ Treatment Control 🔒 |
| [x] Drug Name |
| [x] Dose |
| ┃[x] + Treatment Duration |
| [x] Has a vehicle been used? |
| [x] Specify the vehicle used ⚠ |
| ┃[ ] − Frequency of Administration |
| |
+--------------------------------------------------------------+
| 6 of 7 assigned · 2 pending changes [Discard] [Review & Publish 2 changes] |
+--------------------------------------------------------------+
Deep nesting: The Assign view is full-width (~1200px content area) and comfortably handles depth 6+ with standard 20px indent per level (120px indent at depth 6, leaving >1000px for question text). No focus mode or truncation is required. The overflow-x: auto property on the tree container provides a safety net for extreme depths.
System Questions and Data Extraction¶
An info banner at the top of the Assign view explains how system questions interact with data extraction:
- When data extraction is enabled for the selected stage: system questions (Label and Control questions for each category) are automatically assigned and cannot be removed. System questions provide the structural framework for entity relationships (treatments, disease models, outcomes, cohorts, experiments) required for quantitative data extraction. Custom questions can be freely assigned or unassigned via checkboxes.
- When data extraction is not enabled: system questions at the label and control level can be individually assigned or unassigned. However, assigning any child question will automatically include its parent questions (label and control) to maintain the tree hierarchy.
This distinction matters because system questions define the unit structure (e.g., "Treatment Label" creates treatment units, "Cohort Label" creates cohort units) that quantitative analysis depends on. The banner adapts its wording based on whether the selected stage has data extraction enabled.
Controls¶
Stage selector: Dropdown listing all project stages. Selecting a stage loads its current question assignments.
Show filter toggle: Dropdown with three options:
| Filter | Behaviour |
|---|---|
| All | Shows every question in the category. Checked = assigned, unchecked = unassigned. This is the primary assignment interaction. |
| On stage | Shows only questions in the last published SQS for the selected stage. This is the current published stage baseline that annotators see. |
| Not on stage | Shows only questions not currently in the published SQS for the selected stage. Useful for reviewing gaps and pending additions. |
Tree Behaviour¶
- Single
mat-treecomponent (not two trees) - Checkbox per question node
- System questions: when data extraction is enabled, show a locked checkbox with a dash
--(auto-included, not user-controllable). When data extraction is not enabled, system questions show a regular checkbox and can be assigned/unassigned, but assigning any child question auto-includes the parent system questions. - Checking a child question auto-selects all ancestors (required by parent integrity constraint). Indeterminate checkbox state shown when a parent is checked but not all descendants are.
- Unchecking a parent automatically unchecks all descendants.
- Tree indentation shows hierarchy with hover row highlight.
Assign Row Design — Two Visual Dimensions¶
The Assign page is a configuration tool (check/uncheck to assign questions), not a changeset review. Visual noise is minimised to keep the focus on the checklist interaction. Full changeset detail is shown in the Publish Wizard (see Section 6).
Row elements (left to right): [indent] [checkbox] [+/− prefix] [type icon] [label] [change status icon] [lock/warning badge]
Rows communicate state through exactly two visual dimensions:
Dimension 1: Change status (icon, per-question)
| Indicator | Meaning |
|---|---|
| No indicator | Identical to what's currently published for this stage |
Small amber dot / edit_note |
Has changes that will be included in next publish — whether from admin's own edits OR from another stage's publish (merged concept, no distinction in tree) |
Warning icon (amber warning) |
Validation error that blocks publishing |
Dimension 2: Assignment changes (row treatment)
| Treatment | Meaning |
|---|---|
| Normal row | Currently published on this stage, will remain |
| Left green border + "+" prefix | NOT currently published, will be added |
| Left red border + "−" prefix | Currently published, will be removed |
| Unchecked, no border, muted | Not assigned, never has been |
No row background colours (no green/red fills) and no legend bar. This keeps the tree visually clean for the primary task of checking and unchecking questions.
Only two badge types appear on rows (in addition to the change status icon):
lock(grey) — system question, auto-assignedwarning(amber) — validation error, needs fixing
Status bar (bottom): Simple count format: N of M assigned · N pending changes. No colour-coded breakdown.
Row readability¶
- Hover highlight: Entire row highlights on mouseover to connect label to checkbox
- Compact spacing: Checkboxes are close to the question text
- Long questions: Text wraps within the node. Full text available on hover tooltip.
5. Preview View¶
Layout¶
Full-width interactive annotation form simulation.
+--------------------------------------------------------------+
| [Study] [DMI] [Treatment <-sel] [OA] [Cohort] [Experiment] |
+--------------------------------------------------------------+
| Stage: [Extraction v] |
+--------------------------------------------------------------+
| +----------------------------------------------------------+ |
| | SIMULATION -- data entered here is not saved | |
| +----------------------------------------------------------+ |
| |
| [Interactive annotation form for the selected stage/category] |
| (uses the same AnnotationFormComponent as real annotation, |
| but in simulation mode with no data persistence) |
| |
+--------------------------------------------------------------+
Behaviour¶
- Renders the actual
AnnotationFormComponent(or its v2 replacement) in simulation mode - All controls are interactive -- admins can fill in dummy data to test conditional logic
- No data is saved -- form state is purely local
- Banner at the top clearly states this is a simulation
- Conditional questions appear/disappear based on dummy answers, proving the logic works
- Stage selector controls which question set is previewed
- Category tabs filter to the selected category (consistent with Design and Assign views)
6. Publish Wizard¶
Publishing is organised as a step-by-step wizard to prevent overwhelming the admin with simultaneous decisions. Accessed via "Review & Publish N changes" button on the Assign page action bar.
Wizard Steps¶
Step 1: Review Changes
"Here's what changed since this stage was last published."
Grouped: your edits, updates from other stages, new assignments, removals.
First-publish info card shown here if applicable (see below).
No decisions -- just orientation.
[Next]
Step 2: Confirm Impact on Annotations
For each changed question WITH annotations:
Radio: "Does not affect existing answers" / "May affect"
Pre-populated from Design-time DraftPublishDecisions.
Questions with zero annotations: auto-confirmed.
Objectively invalid annotations: pre-expanded with required decisions.
[Next] (disabled until all confirmed)
Step 3: Configure Answer Handling
(CONDITIONAL -- only appears if Step 2 had "May affect" or objectively invalid items)
Per-question decisions with answer distribution shown.
Mapping configuration for option-based questions.
Separate sections for in-progress and completed sessions.
Pre-populated from Design-time configurations.
[Next] (disabled until all configured)
Step 4: Resolve Conflicts
(CONDITIONAL -- only appears if multi-question conflicts detected)
Sessions where per-question decisions conflict.
Admin resolves each conflict.
[Next] (disabled until all resolved)
Step 5: Review & Publish
Session impact summary: computed effective state.
Final review of all decisions.
Change notes summary.
[Publish]
Step Indicator¶
A progress indicator at the top shows: Review > Confirm impact > [Configure handling] > [Resolve conflicts] > Publish
Conditional steps (3, 4) are greyed out or hidden when not needed. For a simple publish (no annotations or all non-breaking), the wizard is: Step 1 > Step 2 (quick confirmations) > Step 5.
First Publish Info Card¶
A visually distinct info card (not warning) appears in Step 1 (or Step 5) when any questions are being published for the first time:
First-time publish: 2 questions
These questions will become permanent entries in the project.
After publishing, the following properties cannot be changed:
- Category - Data type - Parent relationship - Group as single
You can always change: question text, options, help text,
control type, required/optional, and multiple answer settings.
> "Drug Name" -- Dropdown, Text, under Treatment
> "Dose Regimen" -- Input, Decimal, under Drug Name
Only shown for first-time publishes. Not shown for routine version bumps.
Publish Dialog Sections (Step 1 Detail)¶
- Content changes section (blue edit icon): Lists questions with draft content changes and their diffs. Changes grouped by source -- "Content changes (your edits)" vs "Updated from other stages."
- Questions being added section (green add icon): Lists questions new to this stage.
- Questions being removed section (red remove icon): Lists questions being unassigned.
- Update summary: Sequential label + timestamp (e.g., "Update 3 -- Mar 28, 14:32").
- Change reason: Optional text input.
7. Annotation Form Updates¶
Category Tabs (Unchanged)¶
Category tabs remain as horizontal tabs at the top of the annotation form. No change from current behaviour.
Unit Representation: Mini Cards with Select-to-Show Workspace (New)¶
For categories with units (DMI, Treatment, OA, Cohort, Experiment), unit instances are displayed as mini cards in a wrapping row at the top. Units are NOT currently collapsible -- all questions render inline with no expand/collapse. This is entirely new functionality.
Mini Card Selector Row¶
-- Treatment (3 units) --
+------------+ +==============+ +------------+
| Aspirin | || Saline || | Ibuprofen | [+]
| (complete) | || (2 of 4) || | (not |
| | || || | started) |
+------------+ +==============+ +------------+
[2 of 3 open in workspace] [Open all] [Close all]
- Each card shows: unit label + three-state completion indicator (checkmark / half-filled / empty circle)
- Cards use rectangular styling with structured content (name + status on separate lines) -- NOT pill/chip styling, which implies "selectable tag" rather than "configurable entity"
- Selected/open cards get a highlighted border
- The [+] button is inline for adding new units
- Cards are NOT accordions -- clicking a card opens/closes that unit in the workspace below
Workspace: Multi-Expand with Annotation Form Controls¶
Units open as expandable panels in a workspace below the card row. Multiple units can be open simultaneously for comparison.
Each unit panel shows the actual annotation form controls (not question design tree icons):
- Text questions render as text inputs with labels
- Dropdown questions render as <select> elements
- Radio questions render as radio button groups
- Checkbox questions render as checkboxes
- Conditional nesting: When a parent answer reveals a child question, the child appears indented with a subtle left border. An italic label explains the condition (e.g., "Shown because 'Has a vehicle been used?' is checked").
+-- Saline (control) ----------------------- [expand] [more] [v] --+
| |
| Drug Name: [Saline ] |
| Dose: [10 ml/kg ] |
| Route: [Intraperitoneal v] |
| Duration: [ ] |
| |
| Has a vehicle been used? [x] Yes |
| | Shown because "Has a vehicle been used?" is checked |
| | Specify the used vehicle: [0.5% methylcellulose] |
| |
| Number of animals per group? [12] |
+-------------------------------------------------------------------+
Toolbar¶
- Shows count of open units
- Open all / Close all convenience buttons
Unit Panel Actions¶
Each panel header has: - Expand/collapse chevron: Collapses the panel body (unit stays in workspace but takes minimal space) - Full-screen dialog button (expand icon): Opens the unit in a centered dialog overlay with full width. Shows the same annotation form controls. Useful for complex units with many questions. - Overflow menu (three-dot icon) with: - Hide from workspace: Removes the panel from the workspace. Unit still exists -- click the card to re-open. This is temporary. - Edit label: Rename the unit - Duplicate unit: Copy with "Copy of..." prefix - Delete unit (destructive, red): Shows inline confirmation: "Permanently delete [name] and all its annotations?" Removes both the panel AND the card.
The overflow menu is also available on the mini cards themselves (three-dot icon, top-right), so units can be managed without opening them in the workspace.
Close vs Delete Distinction¶
| Action | Trigger | Effect | Reversible? |
|---|---|---|---|
| Hide from workspace | Overflow menu or X button on panel | Panel removed from workspace view. Card deselected. Unit and data intact. | Yes -- click card to re-open |
| Delete unit | Overflow menu (red action) | Unit permanently deleted. Card removed. All annotations for this unit deleted. | No -- requires confirmation |
Completion Indicators¶
Three-state (no fixed denominator due to conditional questions):
- Checkmark (filled circle with check): All currently-visible questions answered
- Half-filled (circle with dot): Some answered, some remaining
- Empty circle: Nothing answered yet
No numeric counts (e.g., "⅗") because conditional questions change the total dynamically.
Pagination for Many Units¶
When a category has many units (20+), paginate the card row:
- Show 10 cards per page
- Page controls below the card row:
Showing 1-10 of 23 [Prev] [Next] - Lazy-render: only the current page's cards and open panels are in the DOM
- Performance improvement for studies with 20-30+ cohorts/treatments
8. Versioning UX¶
Version Indicators on Tree Nodes¶
Version numbers (v1, v2, v3) are not shown on tree nodes — this is progressive disclosure. The tree shows lifecycle state icons instead (see PDD-04, PDD-17):
- Draft (
edit_notepurple): Never published, no version exists yet - Published (
task_altgreen): Published, matches the last-published version - Published with changes (
published_with_changesamber): Published but has pending edits — publishing will create a new version
Version numbers are only visible in the Version History panel (properties panel, bottom section) and the Version History dialog. Most users don't need to think about version numbers — they just need to know "is this published or does it have changes?"
Version History Timeline¶
Accessible from the properties panel when a published question is selected. Shows a chronological list of all versions:
HISTORY
-------
v3 Mar 15, 2026 Chris "Fixed typo in treatment question"
v2 Mar 10, 2026 Chris "Added 'Subcutaneous' to route options"
v1 Feb 28, 2026 Chris (initial publication)
Each entry shows: version number, date, author, and change reason.
Expandable diff: Clicking a version entry expands to show what changed:
v2 Mar 10, 2026 Chris "Added 'Subcutaneous' to route options"
Options: Oral, IV, IP --> Oral, IV, IP, SC
(no other changes)
Simple before/after per field, only showing fields that actually changed. Not a code diff -- structured field comparison.
Edit Published Question Flow¶
When editing a published question (via the properties panel):
- Properties panel shows current version's content (editable). Changes autosave to the draft (
AQ.draft). - Status icon changes from Published (green
task_alt) to Published with changes (amberpublished_with_changes). - If the question has annotations, the Impact & Mapping section auto-expands in the properties panel (see Section 3, Properties Editor). The admin configures preliminary handling decisions at design time.
- At publish time, the publish wizard (Section 6) loads the
DraftPublishDecisionas a pre-populated suggestion. The admin reviews and confirms in context of all changes together. - On publish: new AQVersion created,
DraftPublishDecisionpromoted to immutablePublishDecision, draft cleared, version history entry added.
9. Accessibility¶
Keyboard Navigation¶
Global (all Question Management views)¶
| Keys | Action | Condition |
|---|---|---|
1-6 |
Switch to category tab 1-6 | When focus is not in a text input |
Ctrl+Shift+P |
Open publish dialog | Assign view (when changes exist) |
Escape |
Exit focus mode / close dialog / deselect | Contextual |
? or Ctrl+/ |
Show keyboard shortcuts cheat sheet | Global |
| Arrow Left/Right | Switch between categories | When category tabs have focus |
Design View -- Tree¶
| Keys | Action |
|---|---|
Up/Down |
Move focus between questions |
Right |
Expand focused node / move to first child |
Left |
Collapse focused node / move to parent |
Enter/Space |
Select focused question (updates properties panel) |
Shift+Up/Shift+Down |
Reorder focused question within siblings |
Home/End |
Jump to first/last visible question |
Ctrl+N |
Add new question (inline placeholder) |
Delete |
Delete selected question (confirmation dialog) |
Ctrl+D |
Duplicate selected question |
F2 |
Focus question text in properties panel |
Design View -- Properties Panel¶
| Keys | Action |
|---|---|
Tab/Shift+Tab |
Move between fields |
Escape |
Return focus to tree |
Ctrl+Z |
Undo last change |
Assign View¶
| Keys | Action |
|---|---|
Up/Down |
Move focus between questions |
Space |
Toggle checkbox |
Shift+Space |
Toggle checkbox + all descendants |
Ctrl+A |
Select all questions |
Ctrl+Shift+A |
Deselect all questions |
Preview View¶
| Keys | Action |
|---|---|
Tab/Shift+Tab |
Move between form fields |
Alt+1/Alt+2 |
Toggle Published/With Unpublished Changes mode |
Dialogs¶
| Keys | Action |
|---|---|
Escape |
Close dialog |
Enter |
Confirm primary action (when not in textarea) |
ARIA Attributes¶
- Tree container:
role="tree" - Tree nodes:
role="treeitem"witharia-expanded,aria-level,aria-setsize,aria-posinset - Group containers:
role="group" - Selected node:
aria-selected="true" - Properties panel:
aria-label="Question properties"witharia-live="polite"for content updates - Form fields:
aria-invalid="true"when validation fails,aria-describedbylinking to error messages - Drag-and-drop:
aria-grabbed,aria-dropeffect(deprecated but still used), plus keyboard alternative
Screen Reader Announcements¶
- When a question is selected: "Selected: [question text], [type], [category], version [N]"
- When a question is reordered: "Moved [question text] to position [N] of [total]"
- When form is saving:
aria-liveregion announces "Saving changes" - When save completes:
aria-liveregion announces "All changes saved" - When validation errors occur: Error messages announced via
aria-live="assertive"
Reduced Motion¶
- All animations respect
prefers-reduced-motion - Drag-and-drop dropzone highlighting uses border changes, not animations
- Tree expand/collapse can be instant rather than animated
Colour Independence¶
- All status indicators (completion, Draft/Published/Published-with-changes states) use both colour AND distinct icon shape — never colour alone
- Assign page pending changes use colour (left border) AND a text character (
+/−) — readable without colour vision - Dropzone indicators use border style changes, not colour alone
10. State Management & Performance¶
Signal-Based Architecture¶
- Question Management store: ngrx SignalStore at the Question Management route level
- Shared state: questions, categories, selected category, selected question ID
- Design-specific: question info map (per-question form state, dirty/valid flags, view state)
-
Assign-specific: stage assignments, filter mode, checkbox states
-
Properties panel: Signal forms with schema-based validation (
required(),validate(),applyWhen()) - No VEST dependency -- use Angular's built-in signal forms validation
- Validation co-located with form definition
-
Immediate feedback via signal-derived error states
-
Annotation form: Signal forms replacing reactive forms
- Per-unit form state (not one giant reactive form)
- Independent validation per unit (isolated, no cross-unit recalculation)
- Conditional question visibility via computed signals (replaces the current Observable +
hiddenproperty approach)
Performance Strategies¶
| Strategy | Where | How |
|---|---|---|
| Category-level lazy loading | Design, Assign | Only build tree data for the selected category. Other categories' trees are not in the DOM. |
| Collapsed unit lazy rendering | Annotation Form | Collapsed unit tiles do not render form fields. Only the expanded unit's form is in the DOM. |
| Unit pagination | Annotation Form | For 20+ units, paginate the tile grid (10 per page). Only current page tiles rendered. |
| Debounced validation | Properties panel | Validation runs on blur or after 300ms of inactivity, not on every keystroke. |
| Optimistic updates | Drag-and-drop, save | Update UI immediately, sync with backend asynchronously. Revert on error. |
| Virtual scrolling | Question tree (if needed) | For categories with 50+ questions, use CDK virtual scroll. Most categories won't need this. |
State Persistence¶
- Selected category: URL query parameter (survives page refresh)
- Selected stage: URL query parameter
- Tree expansion state: Component-level signal (lost on navigation, which is acceptable)
- Draft form changes: Autosaved to backend (debounced). SignalStore tracks autosave status per question, with visual indicator on tree node.
Security: HTML Sanitization¶
All user-provided text (question text, option values, help text, change reasons) must be rendered via Angular's template binding ({{ }} or [textContent]), never via innerHTML or string interpolation into HTML. Angular's built-in sanitization handles escaping. Direct DOM manipulation with user content is prohibited.
11. Research References¶
Patterns and precedents that informed these decisions:
| Design Challenge | Best Precedent | Pattern |
|---|---|---|
| Hierarchical question organization | EPPI-Reviewer code tree | Parent-child tree with category grouping |
| Workspace layout | SurveyJS Creator, Figma | Sidebar tree + properties panel |
| Publishing ceremony | REDCap Development/Production lifecycle | Explicit publish with draft mode for post-publish changes |
| Version tracking | Form.io revision system | Per-publish revision with ID, author, timestamp, notes |
| Stage assignment | REDCap "Designate Instruments for Events" | Checkbox-based assignment, one stage at a time |
| Interactive preview | Qualtrics Preview + Generate Test Responses | Fill dummy data, test branching logic |
| Collapsible repeating units | SurveyJS Dynamic Panel, Cognito Forms | Collapsible instances with dynamic titles + status |
| Performance at scale | Qualtrics blocks + Survey Flow | Category-level rendering + sidebar navigation |
Key finding: No existing tool does per-question versioning. SyRF's AQVersion model is novel. All surveyed tools version at the form/instrument level.
Open Questions¶
Category tab component choice— RESOLVED: Use horizontal tabs with Font Awesome category icons matching the annotation form (fa-file-textStudy,fa-eyedropperDMI,fa-medkitTreatment,fa-eyeOutcome,fa-pawCohort,fa-flaskExperiment). Tabs appear below the view toolbar. Icon source: Production uses Font Awesome icons for continuity with the current annotation form. Material Symbol alternatives for future consideration:description/article(Study),science/biotech(DMI),medication/medical_services(Treatment),visibility/monitoring(Outcome),pets/groups(Cohort),science/experiment(Experiment).Accordion vs multi-expand for unit tiles— RESOLVED: Multi-expand. Multiple units can be open simultaneously for comparison. "Open all" / "Close all" buttons provided.Properties panel width— RESOLVED: Resizable via drag handle on the panel's left edge. Default 360px, min 280px, max 60% viewport width. Session-persisted.- Mobile/responsive behaviour: How does the split panel degrade on small screens? Does the properties panel become a bottom sheet or a full-screen overlay?
Annotation form category tabs— RESOLVED: Yes, same category tabs with icons across all views (Design, Assign, Preview, Review). Category selection persists across view switches.
12. Prototype Design Decisions Addendum¶
Decisions and specifications established during interactive prototyping that augment the original specification. These should be treated as authoritative alongside the sections above.
PDD-01: Navigation Elevation (Supersedes DD-01)¶
Decision: Question Management is elevated to a top-level sidebar section called "Questions", positioned between Stages/Create Stage and Data Export. It is NOT nested under Project Settings.
Rationale: QM is a core workflow (design → assign → preview → publish), not a configuration task like "General" or "Membership". Burying it 3 levels deep under Project Settings did not reflect its importance.
Updated structure:
Project Overview
─────────────
Studies ▸
Screening Info
─────────────
STAGES
Completed Screening [grey dot: no questions]
Data Extraction ▸ [green dot: published, active]
Overview
Review
Settings
Create Stage
─────────────
Questions ▸ [orange dot: has draft changes]
Design
Assign · Extraction [stage context shown inline]
Preview · Extraction
─────────────
Data Export ▸
─────────────
Project Settings ▸
General
Membership
Navigation indicators:
- Stage status dots: Green = published with active sessions. Orange = has draft changes. Grey = no questions assigned.
- Dirty state dot on Questions section: Orange dot when any draft changes exist across the project question set.
- Stage context labels: Assign and Preview nav items show the currently-selected stage inline (e.g., "· Extraction").
- Invisible chevron spacers: Non-expandable items have an invisible chevron to align icons with expandable groups.
- Section dividers: Horizontal lines between Project Overview, Studies/Screening, Stages, Questions, Data Export, and Project Settings.
PDD-02: Design View Layout Toggle¶
Decision: The Design view toolbar includes a layout toggle between "Side Panel" mode (tree + properties panel split) and "Inline" mode (full-width tree with properties expanding below each question node).
Side Panel mode (default):
- Split layout: question tree on left, properties panel on right (1fr | 360px)
- Clicking a question updates the properties panel
- Properties panel shows "Select a question to edit its properties" when nothing is selected
Inline mode:
- Full-width tree, properties panel hidden
- Each question node shows an edit (pencil) icon
- Clicking the edit icon or the question row expands a properties panel directly below the node
- Clicking again collapses it (toggle behaviour)
- Both modes show identical property fields (full parity)
PDD-03: Design View Toolbar¶
Decision: The Design view toolbar (above category tabs) contains:
- Layout toggle — Side Panel / Inline buttons (mat-button-toggle-group style)
- Project Question History button — Opens a dialog to browse and restore previous published versions of the project's questions
PDD-04: Status Icon System (Updated)¶
All status indicators use Material Symbols Outlined icons with tooltips (no worded badges) to reduce visual noise in question trees. Three-state terminology: Draft (never published), Published (clean), Published with changes (published with pending edits).
Question State Icons¶
| State | Icon | Colour | Tooltip | Used in |
|---|---|---|---|---|
| Draft (never published) | edit_note |
Purple (#7b1fa2) | "Draft — not yet published" | Design tree, Properties panel, Assign change status |
| Published (clean) | task_alt |
Green (#4caf50) | "Published" | Design tree, Properties panel |
| Published with changes (published with pending edits) | published_with_changes |
Amber (#e65100) | "Published with unpublished changes" | Design tree, Properties panel, Assign change status |
Note: "Update available" is no longer a separate state. Updates from other stages are merged into the "Published with changes" indicator (amber dot in the Assign view). The distinction between "your edits" and "updates from other stages" is shown in the publish wizard (Step 1) and properties panel on-demand, not in the tree.
Other Indicators¶
| Indicator | Icon/Treatment | Colour | Notes |
|---|---|---|---|
| Required | Red * inline after question text |
Danger red | Mirrors annotation form label convention — NOT a separate dot in the meta column |
| Validation warning | warning icon |
Amber (#e65100) | Design tree: icon in meta + amber row tint. Assign tree: icon in badges column only. |
| System question | lock |
Disabled grey | Both Design and Assign trees |
| Adding to stage | Bold + prefix + green left border |
Success green (#2e7d32) | Assign tree only. Minimal treatment — no row background. |
| Removing from stage | Bold − prefix + red left border |
Danger red | Assign tree only. Minimal treatment — no row background. |
Icon Presentation on Tree Nodes¶
Status icons (right-side column) use a grey outline by default treatment:
- At rest:
filter: grayscale(1); opacity: .4withfont-variation-settings: 'FILL' 0(outline). Icons are a subtle grey hint. - On hover:
filter: none; opacity: .7withFILL 1(filled). Original colour restored. - Selected:
filter: none; opacity: .8withFILL 1. Full colour and fill.
This progressive reveal avoids visual noise when scanning the tree, while still making state information accessible on interaction.
Checkbox Type Icon¶
The Checkbox control type uses select_check_box (outlined empty checkbox) instead of check_box (filled checkbox), to avoid confusion with interactive checkboxes in the UI.
Control Type Icon Map¶
| Control | Icon |
|---|---|
| TextBox / Input | short_text |
| Dropdown | arrow_drop_down_circle |
| Checkbox | select_check_box |
| Radio | radio_button_checked |
| Checklist | checklist |
| Autocomplete | spellcheck |
PDD-05: Properties Panel — Full Field Specification (Updated)¶
All form fields use Material form field outline appearance (mat-form-field appearance="outline") with floating labels that sit on the border.
Fields (in order of appearance — conditionality first, then content, type, behaviour, history, actions):
| Section | Field | Component | Notes |
|---|---|---|---|
| Conditionality | Parent question | Read-only display in highlighted card | "Child of Drug Name" with account_tree icon. Root questions show: "Root question — always visible." |
| Conditionality | Show when | Multi-select chips (dropdown parents) or select (boolean parents) | Boolean: Always / When checked / When unchecked. Dropdown: removable chip per selected parent option, with + Add chip. |
| Conditionality | Option filtering | Expandable "advanced" section | Per parent option, checkboxes control which child options are visible. Validation: filter parent options must be subset of Show When options. |
| Content | Question text | mat-ff text input |
Required |
| Content | Help text | mat-ff textarea |
Hint: "Guidance shown to annotators below the question" |
| Type | Control type | Icon-based toggle selector | Icons: short_text Input, arrow_drop_down_circle Dropdown, select_check_box Checkbox, radio_button_checked Radio, checklist Checklist, spellcheck Autocomplete |
| Type | Data type | Icon-based toggle selector | Icons: text_fields Text, 123 Integer, decimal_increase Decimal, toggle_on Yes/No |
| Type | Options | Scrollable list (max 200px) | Only for Dropdown/Radio/Checklist/Autocomplete |
| Behaviour | Required, Multiple answers, Answer array | mat-checkbox in flex-wrap row |
Single line when panel is wide enough, wraps when narrow |
| Behaviour | Default checkbox status | mat-ff select |
Only for CheckBox controls |
| History | Version history | Clickable entries | Opens master-detail version dialog. Links to "Project question history" |
| Actions | Duplicate / Duplicate with children / Replace with new version / Delete | Ghost buttons | Delete is red (danger). Copies always Draft with new GUIDs. Replace available for published questions. Same actions available in inline mode. |
Conditionality multi-option support: When the parent question has dropdown/radio options, the "Show when" selector uses removable chip tags for selecting multiple parent options. Each selected option appears as a chip with an × remove button. An + Add chip allows adding more options. The question is shown to annotators when the parent answer matches any of the selected options.
Option filtering (advanced): When the child question itself has options AND depends on parent options, an expandable "Option filtering" section appears. For each selected parent option, a checkbox grid controls which of the child's options are visible. Validation rule: parent options used in option filters must be a subset of (or equal to) the parent options in the "Show when" condition.
System question properties: When a system question is selected, the properties panel shows a read-only informative display (not the editable form):
- Role description (e.g., "Unit Label (Treatment)", "Entity Lookup (Disease Models)")
- Quantitative data extraction relevance with
bar_charticon — why it's auto-assigned - Read-only property summary: control type, data type, required status, hierarchy position
- Properties displayed as text labels, not editable form controls
PDD-06: Advanced Options Editor¶
Decision: Options for Dropdown/Radio/Checklist/Autocomplete questions can be managed in two ways:
-
Inline list (default in properties panel): Scrollable list with max-height 200px, drag handles for reorder, inline editing, add/paste/sort actions.
-
Advanced dialog (opened via "Advanced" button): Full spreadsheet-like grid with two columns:
- Option Value — free text, editable
- Parent Answer Mapping — dropdown select from parent question's answers (e.g., "Non-control", "Control")
Advanced dialog features:
- Add row, Sort A-Z, Clear mappings buttons
- Delete row (hover to reveal)
- Bulk paste textarea supporting one-per-line or tab-separated format (
Option Value[TAB]Parent Answer) - Tab navigation between cells
Production implementation: Use Handsontable v14.4.0 (already a project dependency) via the existing handsontable-loader.ts dynamic import pattern and timepoint-spreadsheet.component.ts reference implementation.
PDD-07: Assign View — Layout & Behaviour (Updated)¶
Design principle: The Assign page is a configuration tool (check/uncheck to assign), not a changeset review. Visual treatment is deliberately minimal. The full changeset with all state details is shown in the Review & Publish dialog (PDD-16).
Row structure (left to right, in document flow):
+/−prefix: Bold green+when adding, bold red−when removing. Empty space when unchanged.- Left border: 3px coloured strip — green (adding), red (removing). Transparent when unchanged.
- No row background colours: No green/red/blue fills. Keeps the tree visually clean.
- Change status icons on rows: A small amber dot /
edit_noteicon appears for questions with changes (from own edits or cross-stage updates). No separate "Update Available" indicator — this is merged into the single "changed" state. - Only two badge types:
lock(system question) andwarning(validation error).
Hierarchical checkbox rules:
- Checking a child → all ancestors are automatically checked
- Unchecking a parent → all descendants are automatically unchecked
- Indeterminate state → a parent shows a dash when checked but NOT ALL descendants are checked
- System questions → always checked, disabled, not user-controllable
- Questions with validation errors → checkbox remains enabled (errors are a design concern, not an assignment blocker)
Subtree selection shortcut: Shift+Click on a checkbox selects/deselects the node AND all its descendants. A tooltip on first use hints: "Shift+click to include all children." This enables efficient bulk assignment of entire subtrees (e.g., Drug Name + Dose + Route + Duration in one click).
Filter toggle (toolbar): "Show" label with "All" / "On stage" / "Not on stage" buttons. These are based on the published stage assignment baseline, not the current draft checkbox state. No reference to "SQS" or "PQS" in the UI -- these are internal technical terms only (see developer notes below).
Warning rows: warning icon in badges column. No amber background tint — consistent with minimal treatment.
Cross-stage updates: Merged into the amber "changed" indicator on rows. The distinction between own edits and cross-stage updates is shown in the publish wizard (Step 1), not in the tree.
PDD-08: Assign View — Action Bar & Validation (Updated)¶
Action bar (bottom, sticky):
- Status text:
"N of M assigned · N pending changes"— simple count, no colour-coded breakdown. Changeset detail lives in the publish dialog. - Discard button: "Discard". Disabled (with reduced opacity) when no changes from published baseline.
- Publish button: "Review & Publish N changes" with dynamic count. Disabled when no changes or validation errors exist. Single primary action (replaced separate "Preview & Publish" / "Publish Directly").
Validation panel: Appears above the action bar when configuration errors exist. Uses consistent amber colour (#e65100) throughout — warning icon (not error_outline), "configuration error" label (not "validation error"). Per-error description with "Fix in Design →" link.
Info banner (top of Assign view): Single concise line: "Quantitative data extraction is enabled for this stage — system questions are automatically assigned and locked." Adapts based on stage extraction status.
Cross-stage notice (quiet inline, below the info banner): When questions on this stage have been updated by another stage's publish, a subtle notice appears: "3 questions were updated when Screening was published on Mar 15." This is informational only — not a banner or blocking alert. It disappears after the next publish of this stage.
PDD-09: Preview View — Published vs With Unpublished Changes Toggle¶
Toggle (toolbar): "Published" / "With unpublished changes" buttons
Published mode:
- Shows exactly what annotators currently see
- Simulation banner: "Simulation mode — data entered here is not saved."
With unpublished changes mode:
- Orange banner: "Previewing unpublished changes — N updated, N draft, N removed since last publish"
published with changesbadge on questions with unpublished editsnewbadge on draft questions being added for the first time- Removed questions shown with
−removedbadge, danger-coloured outline, reduced opacity
PDD-10: Category Tab Persistence¶
Decision: Selected category persists across Design/Assign/Preview view switches. Selecting "Treatment" in Design keeps it selected when navigating to Assign or Preview. Implemented via shared selectedCategory state variable that syncs all [data-cat-bar] elements.
PDD-11: Review Page Layout¶
Scope note: The annotation form section of this design (question layout, conditional rendering, unit panels) is within QM v2 scope. The surrounding review page layout (study card, screening sidebar, progress bars) is included for contextual placement and may inform a future Review Page redesign (separate feature brief).
Grid layout: Study card (left, scrollable) + Screening actions sidebar (right, fixed width ~140px)
Progress bars (above study card):
- Screening bar (blue): Three segments — You (solid primary), Remaining (light primary), Unavailable (hatched pattern for studies sufficiently screened by others)
- Annotation bar (green): Three segments — You (solid success), Remaining (light success), Unavailable (hatched)
- Legends with colour keys and counts below each bar
- Tooltips on each segment with exact numbers
Study card (scrollable, max-height 260px):
- Inclusion criteria (green left border) and exclusion criteria (red left border) shown as side-by-side cards
- Screening decision chip: "Included" (green) or "Excluded" (red) — clickable to toggle
- Annotation status chip: "Annotation in progress"
- Full study metadata: title, authors, journal, year, DOI
- Collapsible abstract via
<details>element (starts collapsed) - PDF link
Screening actions sidebar:
- Include (green), Exclude (red), Skip buttons
- Navigation: Previous/Next with study counter
- Annotation: Save, Complete buttons
- Grouped under labelled sections
PDD-12: Annotation Form Question Layout¶
Three-column grid per question row (grid-template-columns: auto 1fr 1fr):
- Branch number — see "Display numbering" below
- Question control — Material outlined form field (
mat-ff) with floating label - Optional Comments — Material outlined textarea with "Optional Comments" floating label
Display numbering: Flat sequential numbering per category (1, 2, 3, ...) with hierarchy communicated by indentation. Numbers reflow when conditional questions are hidden (no gaps). This avoids unwieldy compound labels at depth 4+ and ensures the same question gets a consistent visual position within a category.
Stable identifiers (future Phase 2 enhancement): Each question definition will get a human-readable short code (e.g., TRT.DOSE, COH.SPECIES) for cross-referencing in training materials, discussions, and data exports. These are stage-independent and never change.
Conditional questions: Indented with margin-left: 46px, small subdirectory_arrow_right icon with hover tooltip explaining the condition (not inline text).
Checkbox questions: Flat layout without outline (mat-ff-checkbox pattern).
PDD-13: Unit Panel Fullscreen Dialog¶
Decision: The expand icon (open_in_full) on unit panel headers opens a fullscreen modal dialog (90vw, max 900px) containing the complete annotation form for that unit — all question rows with Material form fields and Optional Comments column. Save and Close buttons in the footer.
PDD-14: Version History Dialogs (Updated)¶
Both version history dialogs use a master-detail layout (not expandable cards):
Individual question version history (opened from Properties panel or inline):
- Left panel (220px): Scrollable list of versions. Each entry shows version ID, timestamp, author, and stage. Published versions use bold text + "Published" badge. Draft snapshots use muted text + "Snapshot" badge.
- Right panel: Detail for the selected version — header with version label + badge, change reason, timestamp. Full properties table (text, help, type, control with icon, required, multiple, options, parent, show when). "Apply as draft" button.
- Clicking a version in the left list instantly updates the right panel.
Project Question History (opened from Design toolbar button or Properties panel link):
- Left panel (220px): Same version list style — published updates with stages and timestamps, plus auto-saved snapshots.
- Right panel: Header with version summary. Below that, the question tree for that version split into a nested master-detail: left half shows the tree with clickable rows and checkboxes, right half shows the selected question's properties at that version.
- Multi-select restore: Checkboxes on each non-system question. "Restore all as draft" button + "Restore N selected" button (enabled when checkboxes are checked, count updates live).
- Individual questions also have an "Apply this question as draft" button in the detail view.
PDD-15: Question Tree Hierarchy (Treatment Category)¶
Corrected hierarchy (matches AnnotationQuestion.cs production code):
Treatment Label (root, system, dropdown)
└── Treatment Control (child, system, checkbox — control/non-control)
└── Drug Name (custom)
└── Dose, Route, Duration
└── Has a vehicle been used? (custom, checkbox)
└── Specify the vehicle used
└── Frequency of Administration (custom)
Treatment Label is the root question (Root = true, SubquestionIds = {TreatmentControlQuestionGuid}). Treatment Control is its child. The same pattern applies to Disease Model Induction (label is root, control is child).
PDD-16: Publish Dialog Structure¶
Dialog content (dynamically generated from current draft state):
- Content changes section (blue edit icon): Lists questions with draft content changes and their diffs
- Questions being added section (green add icon): Lists questions new to this stage
- Questions being removed section (red remove icon): Lists questions being unassigned
- Result card: Shows resulting update summary (e.g., "Update 4 — Mar 28, 14:32").
- Change reason: Optional text input
- Breaking changes: Checkbox "Changes may invalidate existing answers (breaking)"
Access: "Review & Publish N changes" button on Assign page action bar.
Dialog sections (updated terminology):
- Unpublished changes section (
published_with_changesamber icon,~Nprefix): Lists questions with unpublished edits and their field-level diffs. Contextual note: "Publishing creates a permanent version. Annotators on this stage will see the updated questions immediately." - New questions section (
add_circlegreen icon,+Nprefix): Lists questions being published for the first time. - Removing section (
remove_circlered icon,−Nprefix): Lists questions being unassigned from this stage. - Updates from other stages subsection (within "Unpublished changes" section): Changes grouped by source -- "Your unpublished changes" vs "Updated from other stages." Cross-stage updates are shown with their source stage and publish date.
- Result card: Update summary with sequential label and timestamp.
- Change reason: Optional text input.
- Impact confirmation: Per-question confirmation for questions with annotations (feeds into wizard Step 2).
- Publish button: Proceeds to publish wizard Step 2 (or Step 5 if no annotations).
PDD-17: Terminology — Three-State Question Lifecycle¶
Decision: Consistent terminology across all UI: Draft, Published, and Published with changes for the question state. The delta itself is described as unpublished changes.
| State | Term | Icon | Colour | Description |
|---|---|---|---|---|
| Never published | Draft | edit_note |
Purple (#7b1fa2) | Question exists only in the project's draft workspace. Not visible to annotators. |
| Published, no pending edits | Published | task_alt |
Green (#4caf50) | Live on at least one stage. Matches the last-published version exactly. |
| Published, with pending edits | Published with changes | published_with_changes |
Amber (#e65100) | Published version is live, but unpublished changes exist on top of it. Publishing will create a new version. |
Rationale: "Published with changes" keeps the live/published status explicit while still indicating that unpublished work exists on top of it. The change layer itself is described as "unpublished changes". That avoids the ambiguity of terms like "Draft changes", "Changed", or "Not live", which can incorrectly suggest that the whole question is no longer published.
"Update available" (removed as separate state): Updates from other stages are now merged into the "Published with changes" indicator. The distinction between own edits and cross-stage updates is surfaced in the publish wizard (Step 1) and properties panel, not as a separate tree icon.
PDD-18: Quantitative Data Extraction Terminology¶
Decision: All references to "data extraction" in the UI renamed to "quantitative data extraction". All references to "data export" renamed to "quantitative data export".
Rationale: All annotations are a form of data extraction. The qualifier "quantitative" differentiates the specific workflow that requires system questions (entity relationships for meta-analysis) from general annotation data extraction. Aligns with the data export section naming.
Affected UI elements:
- Sidebar navigation: "Quantitative Data Extraction" (stage name), "Quantitative Data Export" (section)
- Assign page info banner: "Quantitative data extraction is enabled for this stage"
- System question properties:
bar_charticon with "Quantitative data extraction" label - All tooltips and descriptions referencing the feature
PDD-19: Breadcrumb Bar — Always Visible¶
Decision: The breadcrumb bar above the question tree is always visible on the Design page, not only during focus mode.
Behaviour:
- No selection: Shows just the category name (e.g., "Treatment") in muted text.
- Question selected: Shows full ancestor path:
Category > Ancestor 1 > Ancestor 2 > Selected Question. Every ancestor is clickable — clicking navigates to and selects that question. - Focus mode active: Same breadcrumb, plus a "Show full tree" button (styled as a subtle outlined button, not underlined text) at the right.
- Category switch: Breadcrumb resets to the new category name.
Fixed height: 34px, single line, overflow: hidden. Never wraps or causes layout shift.
Truncation: Each crumb has max-width: 140px with text-overflow: ellipsis. Full text on hover tooltip.
Overflow: When 4+ ancestors, middle crumbs collapse to a clickable ••• that opens a dropdown showing the hidden path entries. Pattern: Category > Root > ••• > Parent > Selected.
PDD-20: Deep Nesting — Truncation + Focus View¶
Decision: Questions nested beyond depth 5 (0-indexed) are hidden by default behind a truncation link. The truncation link triggers a focus view that re-roots the tree.
Truncation link: Appears as the last child of the deepest visible parent. Styled distinctly from questions:
- Smaller text (11px), italic, muted colour (
text-secondary) - No underline — colour changes to primary blue on hover
- Text: "N more nested questions..."
subdirectory_arrow_righticon (14px, smaller than question type icons)
Focus view (activated by clicking the truncation link):
- Hidden deep children become visible
- Tree re-roots: ancestors above the focus root are hidden (rows + non-path siblings)
- Visual indentation collapses so the focused subtree appears as the root
- Breadcrumb updates to show the full path
- "Show full tree" button appears
Re-root depth calculation: The focus root is chosen so that MAX_VISIBLE_LEVELS (5) levels are shown. If the deep subtree has fewer than 5 levels, the view climbs up ancestors until 5 are displayed.
PDD-21: Adding Questions — Constraint-Aware Mechanisms¶
Decision: Three layered mechanisms for adding questions, respecting the constraint that all custom questions in unit categories must be descendants of the label question.
Layer 1 — Persistent inline "Add question" link: A subtle dashed-border row at the bottom of each valid parent's children list. For Treatment, it appears at the end of Treatment Control's children. For Cohort, at the end of Cohort Label's children. Always visible, in-context.
Layer 2 — Hover-revealed + and ⋮⋮ icons (Notion pattern):
- Appear between the chevron and type icon on hover
+(leftmost): Single action — creates a child question via inline placeholder⋮⋮(rightmost, closest to text): Drag to reorder, click to open actions menu (add child, add above/below, duplicate, duplicate with children, delete)- System questions: neither icon shown (not draggable, adding handled by the inline link)
- Custom questions: both icons present, space reserved via
visibility: hiddenat rest so layout doesn't shift on hover
Layer 3 — Inline placeholder: When any "add" action is triggered, an auto-focused text input appears in the tree at the exact insertion point. Press Enter to create (question immediately selected with properties panel ready). Press Escape to cancel.
No root-level "Add question" button for unit categories (Treatment, DMI, Outcome, Cohort, Experiment) — all custom questions must be descendants of the label. Study category may have a root-level button since it has no label/unit structure.
No browser right-click override: The native browser context menu is preserved. Actions are accessed via the ⋮⋮ grip click.
PDD-22: Unit Panel Header Actions¶
Decision: Each expanded unit panel (on Preview and Review pages) shows four action icons in the header bar:
open_in_full— Open in fullscreen dialogcontent_copy— Duplicate unitdelete(muted/disabled colour) — Delete unit (opens confirmation dialog)more_vert— Overflow menu with: Open in dialog, Edit label, Duplicate, Delete unit
Unit overflow menu is a real popup menu (not alert() placeholders). Delete action shows a confirmation dialog: "Permanently delete [name] and all its annotations? This action cannot be undone."
PDD-23: Annotation Form — Child Row Indentation¶
Decision: Child question rows (1.a., 1.b., 1.c.) in the annotation form are indented 32px from their parent (question 1.). Conditional rows (2.a.) use 46px indent with a left border. This makes the parent-child hierarchy visually clear in the form layout.
PDD-24: Cohort Category — Real System Questions¶
Decision: The Cohort category uses the actual system questions from the codebase (AnnotationQuestion.cs). Unlike Treatment and DMI, Cohort has no Control question — only a Label question with entity lookups.
| Question | Type | System | Purpose |
|---|---|---|---|
| Cohort Label | TextBox | Yes (root) | Identifies each cohort group |
| Disease Models | Dropdown (lookup) | Yes | Links cohort to DMI procedures |
| Treatments | Dropdown (lookup) | Yes | Links cohort to treatment procedures |
| Outcomes | Dropdown (lookup) | Yes | Links cohort to outcome assessments |
| Number of Animals | TextBox (integer) | Yes | Cohort size for quantitative analysis |
Custom questions (Species, Strain, Sex, Age at Procedure, Weight) are children of Cohort Label.
PDD-25: Design Tree Node Layout¶
Decision: The exact element order within each question tree node row, left to right:
Elements marked with * are conditionally visible:
warn-indicator: Absolutely positioned in left margin (outside flow), only on questions with configuration errors+and⋮⋮: In flow butvisibility: hiddenat rest, visible on hover. Not present on system questions.required *: Red asterisk inline after question text, only on required questionsstatus-icon: Right-aligned, grey outline at rest, coloured + filled on hover/selected
Row selection: Selected row has background: rgba(32,52,87,.10) + primary-colour left border. Hover has lighter rgba(32,52,87,.03). Clear visual hierarchy: hover (lightest) < normal < selected (darkest).