Skip to content

Instantly share code, notes, and snippets.

@mvdbeek
Created February 23, 2026 15:42
Show Gist options
  • Select an option

  • Save mvdbeek/9d5a71c5dc0898ab7884af0787c4a0de to your computer and use it in GitHub Desktop.

Select an option

Save mvdbeek/9d5a71c5dc0898ab7884af0787c4a0de to your computer and use it in GitHub Desktop.
Plan: Migrate `data_input` Forms to Client-Side

Plan: Migrate data_input Forms to Client-Side

Context

Galaxy's workflow engine currently defines input forms server-side for data_input steps, requiring server round-trips and complex translation code (step_state_to_tool_state, _parse_state_into_dict). PR #19313 successfully migrated data_collection_input to client-side rendering. This plan extends that pattern to data_input, which is simpler since it manages only three parameters: optional, format, and tag.

Implementation

1. Server: Empty get_inputs() for InputDataModule

File: lib/galaxy/workflow/modules.py (line ~1124)

Replace the body of InputDataModule.get_inputs() with return {} (matching InputDataCollectionModule.get_inputs() at line 1150):

def get_inputs(self):
    # migrated to frontend
    return {}

2. Server: Bypass tool form processing in build_module API

File: lib/galaxy/webapps/galaxy/api/workflows.py (line 537)

Change the from_tool_form condition to also exclude data_input:

from_tool_form = True if module_type not in ("data_collection_input", "data_input") else False

3. Client: Create FormInputDataInput.vue

File: client/src/components/Workflow/Editor/Forms/FormInputDataInput.vue (new)

Follow the pattern of FormInputCollection.vue but simpler — only 3 fields (optional, format, tag). No collection_type, no column definitions, no record field definitions.

The component will:

  • Accept step and datatypes props
  • Use useToolState(stepRef) to parse state
  • Define a ToolState interface with { optional: boolean; format: string | null; tag: string | null }
  • Emit onChange with flat state dict
  • Render FormElement for optional (boolean) and tag (text), and FormDatatype for format

Reusable pieces from existing code:

  • useToolState composable (client/src/components/Workflow/Editor/composables/useToolState.ts)
  • FormElement (client/src/components/Form/FormElement.vue)
  • FormDatatype (client/src/components/Workflow/Editor/Forms/FormDatatype.vue)

4. Client: Route component in FormDefault.vue

File: client/src/components/Workflow/Editor/Forms/FormDefault.vue (line ~46)

Add a new v-if branch for data_input alongside the existing data_collection_input branch:

<FormInputDataInput
    v-if="type == 'data_input'"
    :step="step"
    :datatypes="datatypes"
    @onChange="onChange">
</FormInputDataInput>
<FormInputCollection
    v-else-if="type == 'data_collection_input'"
    ...

Import the new component at the top.

5. Tests

Existing tests that must continue to pass:

  • test/unit/workflows/test_modules.py — unit tests for data_input module (lines 24-83): test_input_has_no_errors, test_data_input_default_state, test_data_input_modified_state, test_data_input_step_modified_state, test_data_input_compute_runtime_state_default, test_data_input_compute_runtime_state_args, test_data_input_connections
  • lib/galaxy_test/selenium/test_workflow_editor.py::TestWorkflowEditor::test_data_input (selenium-only, line 241)

New Playwright test to add:

File: lib/galaxy_test/selenium/test_workflow_editor.py

Add a new test (NOT @selenium_only) that:

  1. Creates a new workflow
  2. Adds a data_input step
  3. Sets label and annotation
  4. Sets the optional toggle, format(s), and tag filter
  5. Saves the workflow
  6. Re-opens and verifies: label, annotation persisted; downloads workflow and verifies tool_state contains optional, format, and tag with correct values
  7. Verifies round-trip: the form shows the correct values after reload

This tests the full client-side rendering + persistence roundtrip. Pattern from test_collection_input_sample_sheet_chipseq_example (line 292).

Extract a shared helper _download_current_workflow is already available (line 972). Also consider extracting shared add-input-and-set-label-annotation logic into a helper to keep tests DRY, since test_data_input, test_collection_input, and the new test all repeat the same pattern.

Files to Modify

File Change
lib/galaxy/workflow/modules.py InputDataModule.get_inputs()return {}
lib/galaxy/webapps/galaxy/api/workflows.py Add data_input to from_tool_form=False condition
client/src/components/Workflow/Editor/Forms/FormInputDataInput.vue New file — client-side form
client/src/components/Workflow/Editor/Forms/FormDefault.vue Route data_input to new component
lib/galaxy_test/selenium/test_workflow_editor.py Add Playwright-compatible test for data_input roundtrip

Verification

  1. Unit tests: pytest test/unit/workflows/test_modules.py — all existing data_input tests must pass
  2. Playwright tests: ./run_tests.sh -playwright lib/galaxy_test/selenium/test_workflow_editor.py::TestWorkflowEditor::test_data_input — both old and new tests
  3. Manual check: The workflow editor should render the data_input form client-side (no build_module round-trip for form inputs), with optional, format, and tag fields working correctly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment