-
Notifications
You must be signed in to change notification settings - Fork 1
UI features #84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UI features #84
Changes from all commits
750c098
b51a2d3
558dc40
91b7c73
af067ca
f2e922f
9129560
28a0c92
95c6b0f
32eba89
c2ef252
821c15f
2c72b4e
198c4e5
116ebff
39e6946
3d7fb7b
607ad0c
67f245c
de0b06d
ac25f17
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -56,6 +56,7 @@ | |||||||||||||||||||||||
| _migrate_timing_add_member_of_timeline, | ||||||||||||||||||||||||
| _migrate_instances_add_member_of_timeline, | ||||||||||||||||||||||||
| _migrate_matrix_cells_add_instance_id, | ||||||||||||||||||||||||
| _migrate_activity_concept_add_href, | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| from .routers import activities as activities_router | ||||||||||||||||||||||||
| from .routers import arms as arms_router | ||||||||||||||||||||||||
|
|
@@ -150,6 +151,7 @@ def _configure_logging(): | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Database migration steps | ||||||||||||||||||||||||
| _migrate_activity_concept_add_href() | ||||||||||||||||||||||||
| _migrate_matrix_cells_add_instance_id() | ||||||||||||||||||||||||
| _migrate_instances_add_member_of_timeline() | ||||||||||||||||||||||||
| _migrate_timing_add_member_of_timeline() | ||||||||||||||||||||||||
|
|
@@ -1961,6 +1963,118 @@ def _matrix_arrays(soa_id: int): | |||||||||||||||||||||||
| return instance_headers, rows | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| def _fetch_enriched_instances(soa_id: int): | ||||||||||||||||||||||||
| """Return enriched instance data with all header information for XLSX export.""" | ||||||||||||||||||||||||
| conn = _connect() | ||||||||||||||||||||||||
| cur = conn.cursor() | ||||||||||||||||||||||||
| cur.execute( | ||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||
| SELECT i.id,i.name,i.instance_uid,i.label,i.member_of_timeline, | ||||||||||||||||||||||||
| v.name AS encounter_name,v.label AS encounter_label, | ||||||||||||||||||||||||
| e.name AS epoch_name,e.epoch_label as epoch_label, | ||||||||||||||||||||||||
| tm.window_label,tm.label AS timing_label,tm.name AS timing_name,tm.value AS study_day | ||||||||||||||||||||||||
| FROM instances i | ||||||||||||||||||||||||
| LEFT JOIN visit v ON v.encounter_uid = i.encounter_uid AND v.soa_id = i.soa_id | ||||||||||||||||||||||||
| LEFT JOIN epoch e ON e.epoch_uid = i.epoch_uid AND e.soa_id = i.soa_id | ||||||||||||||||||||||||
| LEFT JOIN timing tm ON tm.id = v.scheduledAtId AND tm.soa_id = v.soa_id | ||||||||||||||||||||||||
| WHERE i.soa_id=? | ||||||||||||||||||||||||
| ORDER BY COALESCE(i.member_of_timeline, 'zzz'), LENGTH(i.instance_uid), i.instance_uid | ||||||||||||||||||||||||
| """, | ||||||||||||||||||||||||
| (soa_id,), | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| instances = [ | ||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| "id": r[0], | ||||||||||||||||||||||||
| "name": r[1], | ||||||||||||||||||||||||
| "instance_uid": r[2], | ||||||||||||||||||||||||
| "label": r[3], | ||||||||||||||||||||||||
| "member_of_timeline": r[4], | ||||||||||||||||||||||||
| "encounter_name": r[5], | ||||||||||||||||||||||||
| "encounter_label": r[6], | ||||||||||||||||||||||||
| "epoch_name": r[7], | ||||||||||||||||||||||||
| "epoch_label": r[8], | ||||||||||||||||||||||||
| "window_label": r[9], | ||||||||||||||||||||||||
| "timing_label": r[10], | ||||||||||||||||||||||||
| "timing_name": r[11], | ||||||||||||||||||||||||
| "study_day": r[12], | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| for r in cur.fetchall() | ||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||
| conn.close() | ||||||||||||||||||||||||
| return instances | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| def _add_header_rows_to_worksheet(worksheet, enriched_instances): | ||||||||||||||||||||||||
| """Add header rows to a worksheet with instance metadata.""" | ||||||||||||||||||||||||
| # Insert 6 rows at the top for header rows | ||||||||||||||||||||||||
| worksheet.insert_rows(1, 6) | ||||||||||||||||||||||||
|
Comment on lines
+2007
to
+2010
|
||||||||||||||||||||||||
| def _add_header_rows_to_worksheet(worksheet, enriched_instances): | |
| """Add header rows to a worksheet with instance metadata.""" | |
| # Insert 6 rows at the top for header rows | |
| worksheet.insert_rows(1, 6) | |
| HEADER_ROW_COUNT = 6 | |
| def _add_header_rows_to_worksheet(worksheet, enriched_instances): | |
| """Add header rows to a worksheet with instance metadata.""" | |
| # Insert 6 rows at the top for header rows | |
| worksheet.insert_rows(1, HEADER_ROW_COUNT) |
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says '6 rows' but the header construction shows 6 distinct semantic rows (Epoch, Encounter, Instance, Study Day, Timing, Visit Window). Consider adding a comment explaining what each of these 6 rows represents for future maintainability.
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable start_col is initialized to 3 twice (lines 2018 and 2021), which is redundant. The initialization on line 2021 should be removed since col_idx is already set to 3 on line 2018.
| start_col = 3 |
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The magic number 31 represents Excel's maximum sheet name length but is not documented. Define a constant like EXCEL_MAX_SHEET_NAME_LENGTH = 31 to make this constraint explicit and easier to maintain.
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sheet name is truncated to 31 characters (Excel's limit) after adding the 'SoA - ' prefix. If timeline_name is long, this could result in multiple sheets with identical truncated names causing overwrites. Consider truncating timeline_name first to ensure uniqueness: sheet_name = f\"SoA - {timeline_name[:24]}\"
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sanitizing the sheet name happens in two separate steps: truncation first, then character replacement. If the original timeline_name is exactly 31 characters and contains invalid characters that need replacement, the final sheet_name could still be 31 characters but with different content than intended. Consider sanitizing before truncation to ensure consistent behavior.
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate of the same magic string pattern found in _fetch_enriched_instances (line 1982). Both queries use 'zzz' as a sentinel, which should be addressed consistently across both functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The magic string
'zzz'is used as a sentinel value to push unassigned timelines to the end of the sort. This is fragile if timeline UIDs ever start with characters lexicographically after 'z'. Use a more robust approach like a CASE expression or separate the unassigned instances explicitly.