|
27 | 27 | "Export / Save", |
28 | 28 | ) |
29 | 29 |
|
| 30 | +_STATE_TRANSITION_DIAGRAM = """```text |
| 31 | +[Step 1: Scan & Profile] |
| 32 | + ├─ Scan button → discovered_schema, validation_report=None |
| 33 | + └─ Next (enabled when forms discovered) → Step 2 |
| 34 | +
|
| 35 | +[Step 2: Field Mapping] |
| 36 | + ├─ Mapping selectors → mapping_config.mappings |
| 37 | + ├─ Previous → Step 1 |
| 38 | + └─ Next → Step 3 |
| 39 | +
|
| 40 | +[Step 3: Terminology Normalization] |
| 41 | + ├─ Normalization inputs → mapping_config.terminology_lookups |
| 42 | + ├─ Snapshot controls → _wizard_snapshots / mapping_config restore |
| 43 | + ├─ Previous → Step 2 |
| 44 | + └─ Next → Step 4 |
| 45 | +
|
| 46 | +[Step 4: Layout & Visual Configuration] |
| 47 | + ├─ Widget and layout controls → mapping_config.widgets |
| 48 | + ├─ Preview metrics → validation_report |
| 49 | + ├─ Previous → Step 3 |
| 50 | + └─ Next → Step 5 |
| 51 | +
|
| 52 | +[Step 5: Export / Save] |
| 53 | + ├─ Download JSON payload |
| 54 | + ├─ Save locally (.imednet/configs) |
| 55 | + └─ Previous → Step 4 |
| 56 | +
|
| 57 | +Global transitions: |
| 58 | +- Numbered nav buttons jump to any step (1..5) |
| 59 | +- wizard_step is clamped to range 1..5 on every transition |
| 60 | +```""" |
| 61 | + |
| 62 | +_SESSION_STATE_WIREFRAME = "\n".join( |
| 63 | + [ |
| 64 | + "| Wizard step | Primary UI frame | Session state mutations |", |
| 65 | + "| --- | --- | --- |", |
| 66 | + ( |
| 67 | + "| 1 | Scan action + AE/PD/DD form selectors | `discovered_schema`, " |
| 68 | + "`wizard_target_form_*`,<br>`validation_report` reset |" |
| 69 | + ), |
| 70 | + ( |
| 71 | + "| 2 | Canonical target cards with source form/field/fallback controls | " |
| 72 | + "`mapping_config.mappings` |" |
| 73 | + ), |
| 74 | + ( |
| 75 | + "| 3 | Mapping selector + raw→normalized value inputs + snapshot controls | " |
| 76 | + "`mapping_config.terminology_lookups`, `_wizard_snapshots`," |
| 77 | + "<br>`mapping_config` restore/reset |" |
| 78 | + ), |
| 79 | + ( |
| 80 | + "| 4 | Widget type multiselect + layout slider + preview metrics grid | " |
| 81 | + "`mapping_config.widgets`, `validation_report` |" |
| 82 | + ), |
| 83 | + ( |
| 84 | + "| 5 | JSON preview + download + local save action | writes config file " |
| 85 | + "locally; no additional session mutation required |" |
| 86 | + ), |
| 87 | + ] |
| 88 | +) |
| 89 | + |
| 90 | +_UX_REVIEW_NOTES = "\n".join( |
| 91 | + [ |
| 92 | + ( |
| 93 | + "- The setup wizard remains a dedicated page in Streamlit multi-page " |
| 94 | + 'navigation (`st.Page(..., title="Setup Wizard")`) and does not fork ' |
| 95 | + "to separate app routes." |
| 96 | + ), |
| 97 | + ( |
| 98 | + "- In-page progression is controlled by `wizard_step` so reruns preserve " |
| 99 | + "context while users move through numbered tabs and Previous/Next controls." |
| 100 | + ), |
| 101 | + ( |
| 102 | + "- Guardrails are presented inline (`st.info`) when prerequisites are " |
| 103 | + "missing, which aligns with Streamlit's rerun-first interaction pattern." |
| 104 | + ), |
| 105 | + ] |
| 106 | +) |
| 107 | + |
30 | 108 | _CANONICAL_FIELDS = ( |
31 | 109 | ("AE", "event_term", "Adverse Event Term"), |
32 | 110 | ("AE", "severity", "Severity"), |
|
38 | 116 | _WIDGET_TYPES = ("kpi_card", "bar_chart", "line_chart", "data_table") |
39 | 117 |
|
40 | 118 |
|
| 119 | +def _render_design_specification() -> None: |
| 120 | + st.markdown("### Wizard UX design specification") |
| 121 | + st.markdown("#### Flowchart / state transitions") |
| 122 | + st.markdown(_STATE_TRANSITION_DIAGRAM) |
| 123 | + st.markdown("#### Wireframe mapped to session state") |
| 124 | + st.markdown(_SESSION_STATE_WIREFRAME) |
| 125 | + st.markdown("#### UX review: Streamlit multi-page alignment") |
| 126 | + st.markdown(_UX_REVIEW_NOTES) |
| 127 | + |
| 128 | + |
41 | 129 | def _initialise_state(study_key: str) -> None: |
42 | 130 | st.session_state.setdefault(_KEY_WIZARD_STEP, 1) |
43 | 131 | st.session_state.setdefault(_KEY_DISCOVERED_SCHEMA, None) |
@@ -467,6 +555,7 @@ def _step_export(study_key: str) -> None: |
467 | 555 |
|
468 | 556 | def render_page() -> None: |
469 | 557 | st.title("🧭 Study Setup Wizard") |
| 558 | + _render_design_specification() |
470 | 559 |
|
471 | 560 | if not st.session_state.get("_imednet_connected"): |
472 | 561 | st.info("Please connect from the sidebar to configure and publish a study mapping.") |
|
0 commit comments