fix: R script and settings export missing volume unit simplification (#1190)#1228
fix: R script and settings export missing volume unit simplification (#1190)#1228
Conversation
Replace the default flag filter in the save handler with a value-based comparison. Rows where PPSTRESU differs from PPORRESU are treated as changed, regardless of whether the change came from a user edit or an automatic simplification (e.g. volume units). This ensures the volume unit simplification from tab_data.R is captured in session$userData$units_table() and subsequently included in the exported settings and R script. Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
The modal no longer adds a default column when building the table. Custom units are merged by matching on all columns except PPSTRESU and conversion_factor, without needing a tracking flag. Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
The default column is no longer needed in the reactable definition (was hidden) or in the edit handler (was set to FALSE on edit). Change detection is now purely value-based. Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
The units table stored in session$userData$units_table() now only contains rows where PPSTRESU != PPORRESU, so the export paths in nca_setup.R (settings download) and zip-utils.R (ZIP export) no longer need to filter by the default flag. Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
The observer that syncs the local modal_units_table with the global session$userData$units_table no longer uses the default column. Merging is done by matching on all columns except PPSTRESU and conversion_factor. Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
Remove the select(-any_of("default")) guard from tab_nca.R and the
save handler in units_table.R. The default column no longer exists
in the units table, so these guards are unnecessary.
Refs #1190
Co-authored-by: Ona <no-reply@ona.com>
Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
When pknca_data() is created, any units where PPSTRESU differs from PPORRESU (e.g. volume unit simplification) are automatically stored in session$userData$units_table(). This ensures the settings export and R script include these changes even if the user never opens the Units modal. Previously, session$userData$units_table() stayed NULL until the modal was opened and saved, causing settings to export units: ~. Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
PKNCA can produce units rows where PPORRESU and PPSTRESU are both NA (parameters with no derivable units). The comparison NA != NA returns NA, which R treats as truthy in subsetting, causing these rows to leak into the saved units table as .na.character entries. Add explicit is.na() guards in both the auto-populate observer and the modal save handler. Refs #1190 Co-authored-by: Ona <no-reply@ona.com>
There was a problem hiding this comment.
Pull request overview
Fixes an export mismatch in the Shiny NCA workflow where automatic unit simplifications (not performed via the Units modal) were not reflected in exported settings or generated R scripts.
Changes:
- Replace the previous edit-tracking
defaultflag with value-based detection of unit changes (PPSTRESU != PPORRESU). - Remove
defaultcolumn handling across Units modal plumbing and export paths. - Add an observer to auto-populate
session$userData$units_table()frompknca_data()when units differ from defaults.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| inst/shiny/modules/tab_nca/units_table.R | Removes default flag usage; switches to value-based “changed unit” filtering. |
| inst/shiny/modules/tab_nca/nca_setup.R | Removes export-time filtering/stripping of default from units settings. |
| inst/shiny/modules/tab_nca.R | Auto-populates units_table based on PPSTRESU != PPORRESU; removes default drop guard. |
| inst/shiny/functions/zip-utils.R | Stops filtering units by default during ZIP settings export. |
| NEWS.md | Documents the bug fix and the new change-detection behavior. |
| DESCRIPTION | Bumps package version. |
Comments suppressed due to low confidence (3)
inst/shiny/modules/tab_nca/units_table.R:39
dplyr::rows_update()can error ifcustom_unitscontains columns not present indefault_units(e.g., older settings uploads or other sources adding extra cols). Elsewhere the codebase defensively subsets the update table to shared columns before callingrows_update()(seeR/PKNCA.Rwherecustom_units_table[, common_cols, drop = FALSE]is used). Consider applying the same pattern here by restrictingcustom_unitstointersect(names(default_units), names(custom_units))before the update.
if (!is.null(session$userData$units_table())) {
custom_units <- session$userData$units_table()
by_cols <- intersect(names(default_units), names(custom_units))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor"))
dplyr::rows_update(
default_units,
custom_units,
by = by_cols,
unmatched = "ignore"
inst/shiny/modules/tab_nca/units_table.R:212
- Same as above:
rows_update()is passedcustom_unitswithout trimming to shared columns. To avoid runtime errors whensession$userData$units_table()includes extra columns (e.g., from uploaded settings), subsetcustom_unitsto the shared column set before updatingdefault_units(consistent withR/PKNCA.R).
custom_units <- session$userData$units_table()
by_cols <- intersect(names(default_units), names(custom_units))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor"))
dplyr::rows_update(
default_units,
custom_units,
by = by_cols,
unmatched = "ignore"
) %>%
inst/shiny/modules/tab_nca.R:160
- When applying
custom_unitsviarows_update(), consider subsettingcustom_unitsto the shared column set (intersect(names(processed_pknca_data$units), names(custom_units))) before updating. This matches the defensive pattern inR/PKNCA.Rand avoids potential errors ifsession$userData$units_table()ever carries extra columns (e.g., from settings upload).
custom_units <- session$userData$units_table()
by_cols <- intersect(names(processed_pknca_data$units), names(custom_units))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor"))
processed_pknca_data$units <- rows_update(
processed_pknca_data$units,
custom_units,
by = by_cols,
unmatched = "ignore"
| log_trace("Applying custom units specification.") | ||
| modal_units_table() %>% | ||
| dplyr::filter(!default) %>% | ||
| dplyr::filter(!is.na(PPSTRESU), !is.na(PPORRESU), PPSTRESU != PPORRESU) %>% |
There was a problem hiding this comment.
The save handler now persists only rows where PPSTRESU != PPORRESU. This drops user changes where only conversion_factor was edited (allowed via editable = c("PPSTRESU", "conversion_factor")) while keeping the unit label unchanged, so those changes won’t be exported/applied. Consider treating a row as changed when either PPSTRESU != PPORRESU OR conversion_factor != 1 (with appropriate NA handling).
| dplyr::filter(!is.na(PPSTRESU), !is.na(PPORRESU), PPSTRESU != PPORRESU) %>% | |
| dplyr::filter( | |
| (!is.na(PPSTRESU) & !is.na(PPORRESU) & PPSTRESU != PPORRESU) | | |
| dplyr::coalesce(conversion_factor, 1) != 1 | |
| ) %>% |
…y having diffs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Issue
Closes #1190
Description
The volume unit simplification applied in
tab_data.R(e.g.mg*L/mL→mg) was not being captured in the exported settings or R script. This happened becausesession$userData$units_table()only stored rows that the user explicitly edited in the Units modal — it used adefaultflag to track which rows were touched, and the automatic simplification never set that flag.Root cause: The
defaultcolumn (added in #900 / PR #946) tracked edits by flagging rows asdefault = FALSEwhen the user clicked on them in the modal. Automatic changes (like the volume simplification) mutated the PKNCAdata object directly without going through the modal, so they were never flagged.Fix: Replace the
defaultflag with a value-based comparison: rows wherePPSTRESU != PPORRESUare treated as changed. This captures both user edits and automatic simplifications, since any change to the display unit results inPPSTRESUdiffering fromPPORRESU.Changes
units_table.R): Filter byPPSTRESU != PPORRESUinstead of!defaultunits_table.R): Stop addingdefault = TRUE/FALSEcolumns when building the tableunits_table.R): Remove hiddendefaultcolumn definitionunits_table.R): Removedefault <- FALSEassignment on editunits_table.R): Removedefaultfrom merge logicnca_setup.R,zip-utils.R): Removefilter(!default) %>% select(-default)— the units table already contains only changed rowstab_nca.R): Removeselect(-any_of("default"))guardDefinition of Done
session$userData$units_table()custom_units_tabledefaultcolumn fully removed from the units table flowHow to test
custom_units_tablecontains the simplified unitsContributor checklist
.scsschange was done, rundata-raw/compile_css.RNotes to reviewer
defaultcolumn was introduced in PR Enhancement: settings file saves only edited units #946 (issue Enhancement: unit settings only manual changes and not entire units table #900). This PR removes it entirely in favor of value-based detection.PPSTRESUback to equalPPORRESU, that row is correctly treated as unchanged (no need to persist it).devtools::document(),lintr, and tests could not be run locally."