mirror of
https://github.com/wizarrrr/wizarr.git
synced 2026-06-11 23:34:47 -04:00
Add comprehensive "require interaction" functionality for wizard steps that prevents users from proceeding until they engage with step content. ## Key Features: - **Database Integration**: New `require_interaction` boolean field in WizardStep model with migration - **Frontend Gating**: Robust JavaScript system that disables "Next" button until user clicks links/buttons in step content - **UI Enhancement**: Improved checkbox forms with clear descriptions and visual indicators - **Event Handling**: Advanced interaction detection with proper HTMX disabling and event capture - **Admin Interface**: Full integration with wizard configuration forms (main and simple) - **Export/Import**: Support for require_interaction field in wizard step data operations ## Technical Implementation: - Disabled button state management with pointer-events and tabindex control - HTMX attribute manipulation to prevent premature navigation - Event listener capture phase handling for reliable interaction blocking - Comprehensive test coverage for interaction scenarios - Form validation and user experience improvements ## Files Modified: - Backend: models, routes, forms, services, migration - Frontend: JavaScript interaction logic, templates, UI components - Testing: Complete test suite for interaction requirements This feature ensures users engage with critical wizard content before proceeding, improving onboarding experience and preventing accidental step skipping. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
102 lines
3.1 KiB
Python
102 lines
3.1 KiB
Python
from flask_wtf import FlaskForm
|
|
from flask_wtf.file import FileAllowed, FileField, FileRequired
|
|
from wtforms import BooleanField, HiddenField, SelectField, StringField, TextAreaField
|
|
from wtforms.validators import DataRequired, Optional
|
|
|
|
|
|
class WizardStepForm(FlaskForm):
|
|
server_type = SelectField(
|
|
"Server Type",
|
|
choices=[
|
|
("plex", "Plex"),
|
|
("jellyfin", "Jellyfin"),
|
|
("emby", "Emby"),
|
|
("audiobookshelf", "Audiobookshelf"),
|
|
("romm", "Romm"),
|
|
("komga", "Komga"),
|
|
("kavita", "Kavita"),
|
|
],
|
|
validators=[DataRequired()],
|
|
)
|
|
|
|
position = HiddenField("Position", default="0")
|
|
|
|
title = StringField("Title", validators=[Optional()])
|
|
|
|
markdown = TextAreaField("Markdown", validators=[DataRequired()])
|
|
|
|
# Require explicit user interaction before enabling Next
|
|
require_interaction = BooleanField(
|
|
"Require User Interaction",
|
|
default=False,
|
|
description="Block the user continuing, until they click a button or link in this step.",
|
|
)
|
|
|
|
|
|
class WizardPresetForm(FlaskForm):
|
|
"""Form for creating wizard steps from presets."""
|
|
|
|
server_type = SelectField(
|
|
"Server Type",
|
|
choices=[
|
|
("plex", "Plex"),
|
|
("jellyfin", "Jellyfin"),
|
|
("emby", "Emby"),
|
|
("audiobookshelf", "Audiobookshelf"),
|
|
("romm", "Romm"),
|
|
("komga", "Komga"),
|
|
("kavita", "Kavita"),
|
|
],
|
|
validators=[DataRequired()],
|
|
)
|
|
|
|
preset_id = SelectField(
|
|
"Preset",
|
|
choices=[], # Will be populated dynamically
|
|
validators=[DataRequired()],
|
|
)
|
|
|
|
# Variables for preset templates
|
|
discord_id = StringField("Discord Server ID", validators=[Optional()])
|
|
overseerr_url = StringField("Overseerr/Ombi URL", validators=[Optional()])
|
|
|
|
|
|
class WizardBundleForm(FlaskForm):
|
|
"""Simple form to create / edit a WizardBundle."""
|
|
|
|
name = StringField("Name", validators=[DataRequired()])
|
|
description = StringField("Description", validators=[Optional()])
|
|
# optional: Steps selection handled in separate UI; keep form minimal
|
|
|
|
|
|
class SimpleWizardStepForm(FlaskForm):
|
|
"""Minimal form for bundle-only steps (no server_type, no requires)."""
|
|
|
|
title = StringField("Title", validators=[Optional()])
|
|
markdown = TextAreaField("Markdown", validators=[DataRequired()])
|
|
|
|
# Allow interaction requirement for custom/bundle steps as well
|
|
require_interaction = BooleanField(
|
|
"Require User Interaction",
|
|
default=False,
|
|
description="Block the user continuing, until they click a button or link in this step.",
|
|
)
|
|
|
|
|
|
class WizardImportForm(FlaskForm):
|
|
"""Form for importing wizard steps or bundles from JSON files."""
|
|
|
|
file = FileField(
|
|
"JSON File",
|
|
validators=[
|
|
FileRequired("Please select a JSON file to import."),
|
|
FileAllowed(["json"], "Only JSON files are allowed."),
|
|
],
|
|
)
|
|
|
|
replace_existing = BooleanField(
|
|
"Replace Existing",
|
|
default=False,
|
|
description="Check to replace existing data, leave unchecked to merge with existing.",
|
|
)
|