Overview
Column values display custom data in workflow tables, showing information like patient names, file names, or other key data extracted from the workflow context. They can be defined at the workflow level (all steps) or step level (overrides).
Basic Usage
Workflow-Level Columns
Define columns that appear for all steps using the Workflow
constructor:
from workflows_py.workflow import Step, ScreenStep, Workflow
workflow = Workflow(
get_display_col_values={
"Patient ID": lambda ctx: ctx.get_start_data().get("patientId", ""),
"Started By": lambda ctx: ctx.current_user["name"] if ctx.current_user else "Unknown",
}
)
Step-Level Columns (Overrides)
Individual steps can override or add columns:
workflow.then(
Step(
"process-documents",
process_documents_function,
get_display_col_values={
"File Name": lambda ctx: ctx.get_step_result("document-upload")["documents"][0]["fileName"],
"Patient ID": lambda ctx: ctx.get_start_data().get("patientId", "N/A"), # Overrides workflow-level
}
)
)
Column Value Structure
The get_display_col_values
parameter is a dictionary where:
- Keys: Column names displayed in the interface
- Values: Lambda functions that receive
WorkflowRunContext
and return a string or None
None
values: Display as ”—” (em dash)
Data Sources
Start Data
"Patient ID": lambda ctx: ctx.get_start_data().get("patientId", ""),
"Priority": lambda ctx: ctx.get_start_data().get("priority", "Normal"),
Step Results
"File Name": lambda ctx: ctx.get_step_result("document-upload")["documents"][0]["fileName"],
"Doc Count": lambda ctx: str(len(ctx.get_step_result("document-upload")["documents"])),
"Started By": lambda ctx: ctx.current_user["name"] if ctx.current_user else "Unknown",
"User Email": lambda ctx: ctx.current_user["email"] if ctx.current_user else "",
Safe Data Access
Always handle missing data gracefully:
get_display_col_values={
# Safe access with defaults
"Patient Name": lambda ctx: ctx.get_start_data().get("patientName", "N/A"),
# Safe nested access
"File Name": lambda ctx: (
ctx.get_step_result("upload")["documents"][0]["fileName"]
if ctx.get_step_result("upload")
and "documents" in ctx.get_step_result("upload")
and len(ctx.get_step_result("upload")["documents"]) > 0
else "No file"
),
# Safe string formatting
"Full Name": lambda ctx: (
f"{ctx.get_start_data().get('firstName', '')} {ctx.get_start_data().get('lastName', '')}"
if ctx.get_start_data().get('firstName') and ctx.get_start_data().get('lastName')
else ""
).strip(),
}
Best Practices
- Use descriptive column names:
"Patient ID"
not "ID"
- Provide fallback values: Always use
.get()
with defaults
- Format data appropriately: Truncate dates, format numbers
- Keep lambdas simple: Move complex logic to separate functions
def get_patient_display_name(ctx):
first = ctx.get_start_data().get('firstName', '')
last = ctx.get_start_data().get('lastName', '')
if first and last:
return f"{first[:1]}. {last}"
return first or last or "Unknown"
get_display_col_values={
"Patient": get_patient_display_name,
}
Column Inheritance
Column ordering follows a specific pattern based on the order columns are defined in the dictionary:
Ordering Rules
- Workflow-level columns appear first in the order they were defined
- Step-level columns with the same key/name override workflow-level columns but maintain their original position
- Step-level columns with different keys are appended to the end in the order they were defined
Example
workflow = Workflow(
get_display_col_values={
"Status": lambda ctx: "Default",
"Patient ID": lambda ctx: ctx.get_start_data().get("patientId", ""),
"Started By": lambda ctx: ctx.current_user["name"] if ctx.current_user else "Unknown",
}
)
workflow.then(
Step(
"process-step",
process_function,
get_display_col_values={
"Status": lambda ctx: "Processing", # Overrides workflow "Status" at position 1
"File Name": lambda ctx: "document.pdf", # New column, appended at the end
"Patient ID": lambda ctx: ctx.get_start_data().get("patientId", "N/A"), # Overrides at position 2
}
)
)
# Final column order: Status (overridden), Patient ID (overridden), Started By (inherited), File Name (appended)
This ensures consistent column ordering across all workflow steps while allowing step-specific customization.
Complete Example
from workflows_py.workflow import ScreenStep, Step, Workflow
def process_patient_data(ctx):
return {"processed": True}
workflow = Workflow(
get_display_col_values={
"Patient ID": lambda ctx: ctx.get_start_data().get("patientId", ""),
"Patient Name": lambda ctx: (
f"{ctx.get_start_data().get('patientFirstName', '')[:1]} {ctx.get_start_data().get('patientLastName', '')}"
if ctx.get_start_data().get("patientFirstName") and ctx.get_start_data().get("patientLastName")
else ""
).strip(),
"Started By": lambda ctx: ctx.current_user["name"] if ctx.current_user else "Unknown",
}
)
workflow.then(
ScreenStep(
"document-upload",
screen_path="./screens/document-upload-screen.tsx"
)
).then(
Step(
"process-patient-data",
process_patient_data,
get_display_col_values={
"File Name": lambda ctx: ctx.get_step_result("document-upload")["documents"][0]["fileName"],
"Status": lambda ctx: "Processing" if ctx.get_step_result("process-patient-data")["processed"] else "Pending",
}
)
)