Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6a3272d
refactor: detect unit changes by comparing PPSTRESU vs PPORRESU
Gero1999 Apr 15, 2026
f750289
refactor: remove default flag from units table modal open logic
Gero1999 Apr 15, 2026
dc64958
refactor: remove default column from reactable and edit handler
Gero1999 Apr 15, 2026
be27b41
refactor: remove default flag filtering from settings export
Gero1999 Apr 15, 2026
339b559
refactor: remove default flag from global units_table observer
Gero1999 Apr 15, 2026
aa406cd
cleanup: remove residual default column guards
Gero1999 Apr 15, 2026
b66eec9
chore: bump version to 0.1.0.9150 and update NEWS.md
Gero1999 Apr 15, 2026
4b4de94
fix: auto-populate units_table from simplified PKNCAdata units
Gero1999 Apr 15, 2026
5b9b913
fix: exclude NA rows from units change detection
Gero1999 Apr 15, 2026
e372eb1
address if the user loads new data with no unit diffs after previous…
Gero1999 Apr 15, 2026
f4f71d2
fix: store full units table internally, filter to changed rows on export
Gero1999 Apr 20, 2026
d8b6875
fix: merge imported units into full data-derived table on settings up…
Gero1999 Apr 20, 2026
a6de2cf
Merge branch 'main' into 1190-fix/units-table-detect-changes-by-value
Gero1999 Apr 22, 2026
9d9f9c4
Bump version to 0.1.0.9153
Gero1999 Apr 22, 2026
8b53792
refactor: reduce cyclomatic complexity of tab_nca_server
Gero1999 Apr 27, 2026
1f311a3
Merge branch 'main' into 1190-fix/units-table-detect-changes-by-value
Gero1999 Apr 28, 2026
f84ee0f
Merge remote-tracking branch 'origin/main' into 1190-fix/units-table-…
Gero1999 Apr 29, 2026
840102e
revert: remove auto-replay system, keep only units-table changes
Gero1999 Apr 29, 2026
c511bd1
Merge main into 1190-fix/units-table-detect-changes-by-value
Gero1999 Apr 30, 2026
5b501d3
fix: isolate settings_override read in units auto-populate observer
Gero1999 Apr 30, 2026
6b6a464
Merge main into branch
Gero1999 May 4, 2026
6b0dcfd
refactor: extract .sync_units_table to reduce tab_nca_server complexity
Gero1999 May 8, 2026
e6ebd6d
fix: simplify .sync_units_table to avoid auto-replay interference
Gero1999 May 8, 2026
a57dcc4
fix: populate units_table lazily inside res_nca instead of observer
Gero1999 May 8, 2026
e94ce34
fix: decouple units_table from settings() reactive to prevent debounc…
May 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@


## Bugs fixed
* R script and settings export now include volume unit simplifications. Unit change detection uses value comparison (`PPSTRESU != PPORRESU`) instead of an edit-tracking flag, so automatic simplifications (e.g. `mg*L/mL` → `mg`) are captured alongside user edits (#1190)
* Fixed ratio calculations with `Aggregate Subject = yes` or `if-needed` not aggregating reference values, and ratio parameter columns (FABS, FREL, etc.) not appearing in NCA Results (#1273)
* Last dose interval end time now extends to the last observed sample instead of being cut off at TRTRINT (tau), ensuring all collected data points are included in NCA calculations (#1235)
* Fixed NA `PPSTRESU` handling across NCA results: descriptive statistics no longer crash when a parameter group has all-NA units, and manual interval parameters (e.g., RCAMINT) no longer get `NA` appended to their column names (#1216)
Expand Down
10 changes: 6 additions & 4 deletions inst/shiny/functions/zip-utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -523,10 +523,12 @@ prepare_export_files <- function(target_dir,
.export_settings <- function(target_dir, session) {
settings_list <- session$userData$settings()

if (!is.null(settings_list$units)) {
settings_list$units <- settings_list$units %>%
dplyr::filter(!default) %>%
dplyr::select(-default)
# Units are stored separately from settings() to avoid triggering
# the settings debounce cascade. Read directly for export.
units_snapshot <- session$userData$units_table()
if (!is.null(units_snapshot)) {
settings_list$units <- units_snapshot %>%
dplyr::filter(!is.na(PPSTRESU), !is.na(PPORRESU), PPSTRESU != PPORRESU)
}

settings_list$ratio_table <- session$userData$ratio_table()
Expand Down
9 changes: 6 additions & 3 deletions inst/shiny/modules/tab_nca.R
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,7 @@ tab_nca_server <- function(id, pknca_data, extra_group_vars, settings_override,
# Update units table
processed_pknca_data <- processed_pknca_data()
if (!is.null(session$userData$units_table())) {
custom_units <- select(
session$userData$units_table(), -any_of("default")
)
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(
Expand All @@ -214,6 +212,11 @@ tab_nca_server <- function(id, pknca_data, extra_group_vars, settings_override,
by = by_cols,
unmatched = "ignore"
)
} else {
# First NCA run: populate units_table from the data so settings
# export includes volume-simplified units even if the user never
# opens the Units modal.
session$userData$units_table(processed_pknca_data$units)
}

#' Calculate results
Expand Down
28 changes: 23 additions & 5 deletions inst/shiny/modules/tab_nca/nca_setup.R
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,23 @@ nca_setup_server <- function(id, data, adnca_data, extra_group_vars, settings_ov
has_full_units <- all(c("PPORRESU", "conversion_factor") %in% names(imported_units))

if (has_full_units) {
session$userData$units_table(imported_units)
# Imported settings contain only changed rows (PPSTRESU != PPORRESU).
# Merge them into the full data-derived units table so downstream code
# that expects the complete table (e.g. nca_results.R) works correctly.
observe({
req(processed_pknca_data())
data_units <- processed_pknca_data()$units
by_cols <- intersect(names(data_units), names(imported_units))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor"))
merged <- rows_update(
data_units,
imported_units,
by = by_cols,
unmatched = "ignore"
)
session$userData$units_table(merged)
}) %>%
bindEvent(processed_pknca_data(), once = TRUE)
} else {
# Defaults-only format: wait for data-derived units, then resolve.
observe({
Expand Down Expand Up @@ -231,10 +247,12 @@ nca_setup_server <- function(id, data, adnca_data, extra_group_vars, settings_ov
},
content = function(con) {
export_settings <- final_settings()
if (!is.null(export_settings$units)) {
export_settings$units <- export_settings$units %>%
filter(!default) %>%
select(-default)
# Units are stored separately from settings() to avoid triggering
# the settings debounce cascade. Read directly for export.
units_snapshot <- session$userData$units_table()
if (!is.null(units_snapshot)) {
export_settings$units <- units_snapshot %>%
filter(!is.na(PPSTRESU), !is.na(PPORRESU), PPSTRESU != PPORRESU)
Comment thread
Gero1999 marked this conversation as resolved.
}
export_settings$ratio_table <- ratio_table()
payload <- list(
Expand Down
3 changes: 1 addition & 2 deletions inst/shiny/modules/tab_nca/setup/settings.R
Original file line number Diff line number Diff line change
Expand Up @@ -502,8 +502,7 @@ settings_server <- function(id, data, adnca_data, settings_override) {
is.checked = input$LAMZSPN_rule,
threshold = input$LAMZSPN_threshold
)
),
units = session$userData$units_table()
)
)
})

Expand Down
22 changes: 8 additions & 14 deletions inst/shiny/modules/tab_nca/units_table.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ units_table_server <- function(id, mydata) {

modal_units_table <- reactiveVal(NULL)
observeEvent(input$open_units_table, {
default_units <- mydata()$units %>%
dplyr::mutate(default = TRUE)
default_units <- mydata()$units

if (!is.null(session$userData$units_table())) {
custom_units <- dplyr::mutate(session$userData$units_table(), default = FALSE)
custom_units <- session$userData$units_table()
by_cols <- intersect(names(default_units), names(custom_units))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor", "default"))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor"))
dplyr::rows_update(
default_units,
custom_units,
Expand Down Expand Up @@ -102,8 +101,7 @@ units_table_server <- function(id, mydata) {
PPORRESU = colDef(name = "Default Unit"),
PPSTRESU = colDef(name = "Custom Unit"),
conversion_factor = colDef(name = "Conversion Factor"),
is_hidden = colDef(show = FALSE),
default = colDef(show = FALSE)
is_hidden = colDef(show = FALSE)
),
pagination = FALSE,
filterable = TRUE,
Expand Down Expand Up @@ -156,7 +154,6 @@ units_table_server <- function(id, mydata) {
)
}

modal_units_table[info$row, "default"] <- FALSE
modal_units_table[info$row, "conversion_factor"] <- conversion_factor_value
}

Expand Down Expand Up @@ -192,22 +189,19 @@ units_table_server <- function(id, mydata) {
}

log_trace("Applying custom units specification.")
modal_units_table() %>%
dplyr::filter(!default) %>%
session$userData$units_table()
session$userData$units_table(modal_units_table())

# Close the modal message window for the user
removeModal()
})

#' Update local `modal_units_table()` if the global value changes.
observeEvent(session$userData$units_table(), {
default_units <- mydata()$units %>%
dplyr::mutate(default = TRUE)
default_units <- mydata()$units

custom_units <- dplyr::mutate(session$userData$units_table(), default = FALSE)
custom_units <- session$userData$units_table()
by_cols <- intersect(names(default_units), names(custom_units))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor", "default"))
by_cols <- setdiff(by_cols, c("PPSTRESU", "conversion_factor"))
dplyr::rows_update(
default_units,
custom_units,
Expand Down
Loading