Source code for imednet_streamlit.components.data_lineage

"""Data Lineage components.

Provides utilities for redacting sensitive fields and rendering multi-pane
views that trace the transformation of raw EDC records into canonical models.
"""

from __future__ import annotations

from typing import Any

import pandas as pd


[docs]def render_lineage_panes( *, raw_record: dict[str, Any] | None, mapping_rules: list[dict[str, Any]], canonical_payload: dict[str, Any], ) -> None: """Render side-by-side lineage panes for raw, mapping, and canonical views.""" # Import inside function so tests can patch `streamlit` via sys.modules. import streamlit as st c1, c2, c3 = st.columns(3) with c1: st.subheader("Raw EDC Payload") if raw_record: st.json(_redact_sensitive_keys(raw_record)) else: st.info("Raw record context unavailable.") with c2: st.subheader("Transformation Matrix") if mapping_rules: st.dataframe(pd.DataFrame(mapping_rules), use_container_width=True) else: st.info("Direct passthrough (No translation required).") with c3: st.subheader("Canonical Target") st.json(_redact_sensitive_keys(canonical_payload))
def _redact_sensitive_keys(data: dict[str, Any]) -> dict[str, Any]: """Redact standard sensitive keys from payloads for secure display.""" sensitive_keys = {"patient_name", "ssn", "dob", "mrn"} redacted: dict[str, Any] = {} for k, v in data.items(): if k.lower() in sensitive_keys: redacted[k] = "***MASKED***" elif isinstance(v, dict): redacted[k] = _redact_sensitive_keys(v) else: redacted[k] = v return redacted