Skip to content

Protein-turnover followups: MSstats-format CSV download, imputation help text, template-gated contrast UI#215

Merged
tonywu1999 merged 6 commits into
develfrom
MSstatsShiny/work/20260528_protein_turnover_easy_followups
Jun 3, 2026
Merged

Protein-turnover followups: MSstats-format CSV download, imputation help text, template-gated contrast UI#215
tonywu1999 merged 6 commits into
develfrom
MSstatsShiny/work/20260528_protein_turnover_easy_followups

Conversation

@swaraj-neu

@swaraj-neu swaraj-neu commented Jun 2, 2026

Copy link
Copy Markdown
Contributor
  • Load page: add "Download MSstats-format CSV" button per converter, enabled after conversion, written via data.table::fwrite.
  • QC/help text: state both imputation preconditions across the QC description, MBi tooltip, and help page.
  • Statmodel: hide contrast-matrix header and workflow bullet for the turnover and chemoproteomics templates, gated by app_template().

Motivation and Context

This PR implements three key enhancements to the protein-turnover analysis workflow in MSstatsShiny:

  1. MSstats-format CSV Download: Adds a convenient download button on the load page to export processed data in MSstats format after data conversion completes.

  2. Imputation Help Text Clarification: Improves user guidance by explicitly documenting both preconditions for running feature imputation (protein must have at least one observed feature in the run AND the missing feature must be observed in at least one other run) across the QC description, model-based imputation tooltip, and help page.

  3. Template-Gated Contrast UI: Hides the contrast matrix definition section and the default workflow step for protein-turnover and chemoproteomics templates, since these templates use response-curve analysis instead of traditional contrasts. This simplifies the UI for template-specific workflows.

Detailed Changes

Data Export Functionality

  • R/module-loadpage-server.R (+40 lines): Implemented download handler for MSstats-formatted data

    • Manages UI control state: disables download button when "Upload Data" is clicked, re-enables when get_data() becomes available
    • Exports single data.frame as CSV (MSstats_format-<date>.csv)
    • Exports multiple named tables as ZIP containing individual CSV files
    • Uses data.table::fwrite() for efficient writing
  • R/module-loadpage-ui.R (+9/-2 lines): Extended action button section

    • Replaces single disabled proceed button with flex-styled container
    • Adds disabled "Download MSstats-format CSV" button via downloadButton() and shinyjs::disabled()

Help Text and Documentation

  • R/module-qc-ui.R (+2/-2 lines): Enhanced imputation documentation

    • Updated QC header description to clarify feature summarization and imputation behavior
    • Expanded model-based imputation tooltip to explain that unchecked state uses censored-value cutoff instead
  • R/module-help-ui.R (+6/-1 lines): Reformatted imputation help text

    • Moved "Censoring assumptions:" label to its own line for clarity
    • Improved readability of censoring assumption explanations

Template-Specific UI Visibility Control

  • R/module-statmodel-server.R (+9 lines): Template-aware UI management via observeEvent(app_template())

    • For protein_turnover template: hides contrast-matrix header and default workflow bullet, shows response-curve workflow bullet
    • For chemoproteomics template: applies same hide/show behavior
    • For all other templates: shows contrast header and default bullet, hides response-curve bullet
    • Uses shinyjs::hide() and shinyjs::show() with asis = TRUE for DOM targeting
  • R/statmodel-ui-comparisons.R (+1 line): Added explicit DOM targeting

    • Assigned id = "statmodel_contrast_header" to contrast-matrix header h4 element
  • R/statmodel-ui-headers.R (+6/-1 lines): Restructured workflow bullets for conditional display

    • Added id = "statmodel_workflow_bullet_default" to default workflow step
    • Added id = "statmodel_workflow_bullet_response_curve" to response-curve step
    • Wrapped response-curve bullet in shinyjs::hidden() for initial visibility control

Unit Tests

No new unit tests were added or modified in this PR. The following test coverage gaps exist:

  • No tests for the download_msstats_format download handler functionality (single data.frame vs. multiple tables, ZIP creation, file naming)
  • No tests for template-gated visibility of contrast header and workflow bullets
  • No tests for updated imputation help text rendering
  • Existing test suites in tests/testthat/test-module-loadpage-ui.R, tests/testthat/test-module-statmodel-ui.R, and tests/testthat/test-module-statmodel-server.R were not extended

Coding Guidelines

No violations of standard R or Shiny coding practices are evident in this PR. The implementation:

  • Follows established naming conventions (download_msstats_format, statmodel_contrast_header, statmodel_workflow_bullet_*)
  • Uses reactive patterns appropriately with observeEvent() and reactive()
  • Properly manages temporary directories with on.exit() cleanup for ZIP creation
  • Maintains module namespace isolation using ns() and NS()
  • Leverages existing utility functions (data.table::fwrite(), utils::zip())

Recommendation: While not a violation per se, best practice suggests adding unit tests for the new download handler and template visibility logic to ensure maintainability and prevent regressions.

- Load page: add "Download MSstats-format CSV" button per converter,
  enabled after conversion, written via data.table::fwrite.
- QC/help text: state both imputation preconditions across the QC
  description, MBi tooltip, and help page.
- Statmodel: hide contrast-matrix header and workflow bullet for the
  turnover and chemoproteomics templates, gated by app_template().
@swaraj-neu swaraj-neu requested a review from tonywu1999 June 2, 2026 19:50
@swaraj-neu swaraj-neu self-assigned this Jun 2, 2026
@swaraj-neu swaraj-neu added the enhancement New feature or request label Jun 2, 2026
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@swaraj-neu, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 47 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a37a1c2-434b-4fe9-a318-dc012849729b

📥 Commits

Reviewing files that changed from the base of the PR and between d35c116 and 78a2756.

📒 Files selected for processing (1)
  • R/module-loadpage-server.R
📝 Walkthrough

Walkthrough

This PR enhances MSstatsShiny with three functional improvements: clarified help documentation for data imputation and censoring assumptions, a new download feature to export processed data in MSstats CSV format, and template-driven conditional UI visibility for statistical model configuration workflows.

Changes

UI Enhancements and Data Export

Layer / File(s) Summary
Help and documentation text improvements
R/module-help-ui.R, R/module-qc-ui.R
Help text reformatted for missing-value imputation and censoring assumptions; QC header description and model-based imputation tooltip expanded to clarify when imputation runs, when it is skipped, and how censored-value cutoffs are used.
MSstats format data export feature
R/module-loadpage-ui.R, R/module-loadpage-server.R
New "Download MSstats-format CSV" button added to action buttons area; server wires download handler to disable during upload, enable when data loads, and export as date-stamped CSV for single data frames or date-stamped ZIP of per-table CSVs for multi-table results.
Template-based conditional UI visibility
R/statmodel-ui-headers.R, R/statmodel-ui-comparisons.R, R/module-statmodel-server.R
Workflow bullet and contrast header elements tagged with explicit DOM ids; template-selection logic in statmodelServer conditionally shows/hides contrast header and default/response-curve workflow bullets based on selected statistical model template.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Vitek-Lab/MSstatsShiny#117: Modifies header construction in R/statmodel-ui-headers.R by adding workflow bullet elements and hidden response-curve bullet logic that this PR builds upon.
  • Vitek-Lab/MSstatsShiny#119: Touches template-driven Shiny UI show/hide logic in R/module-statmodel-server.R connected to the same visibility-control code paths.
  • Vitek-Lab/MSstatsShiny#154: Wires enable/disable flow around data processing in loadpageUI/loadpageServer that integrates with the new download control.

Suggested reviewers

  • tonywu1999

Poem

🐰 A rabbit's ode to your refactored flows,
Download buttons now, where visibility grows,
Templates dance with conditionals bright,
Help text clarified—documentation takes flight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title comprehensively covers the three main features added: MSstats-format CSV download, imputation help text updates, and template-gated contrast UI visibility changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MSstatsShiny/work/20260528_protein_turnover_easy_followups

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DESCRIPTION`:
- Around line 46-47: The two roxygen2 version fields are inconsistent: update
both the Config/roxygen2/version and the RoxygenNote entries in DESCRIPTION to
the same intended roxygen2 version (pick either 8.0.0 or 7.3.3 consistently),
save the file, and then regenerate the package documentation (run
roxygen2/devtools::document or equivalent) so the Rd/NAMESPACE artifacts match
the chosen version and avoid spurious diffs.

In `@R/module-loadpage-server.R`:
- Around line 571-578: The download handler output$download_msstats_format
currently always calls data.table::fwrite(get_data(), file) but get_data() can
return a list with PTM and PROTEIN tables; update the handler to detect that
case and branch: if get_data() is a single data.frame write it as before, but if
it's a list containing elements like PTM and PROTEIN then either disable/hide
this download (e.g., return or show a message) or export the appropriate
MSstats-formatted table(s) separately (e.g., write PTM and PROTEIN to separate
CSVs or combine into a single export), ensuring you reference get_data(),
output$download_msstats_format and use data.table::fwrite for each table
written.
- Around line 566-568: The export button is only enabled in the
observeEvent(get_data()) handler so it can remain enabled when upstream inputs
change or a later conversion fails; add logic to disable the
"download_msstats_format" control whenever upstream inputs that affect
conversion change (e.g., file selection inputs and any controls used by the
eventReactive triggered by input$proceed1) and ensure the button is only
re-enabled inside the successful conversion observer (observeEvent(get_data()))
after req(get_data()) succeeds; also explicitly disable the button in the
conversion error path so stale exports cannot be downloaded (reference
observeEvent(get_data()), get_data(), eventReactive(input$proceed1, ...), and
shinyjs::enable/"download_msstats_format").

In `@R/module-qc-ui.R`:
- Line 25: Summary: The UI copy in the p(...) call promises CSV downloads for
"all outputs" but plots are not downloadable. Update the paragraph string in
R/module-qc-ui.R (the p(...) element that currently mentions "All outputs are
available to download in 'csv' format") to accurately state that only summarized
tables and processed datasets are available as CSV downloads and that plot
export is not currently provided (or will be provided separately), so users
aren't misled by the claim referencing plot export at lines ~217-218.

In `@R/statmodel-ui-headers.R`:
- Around line 44-45: Update the default workflow bullet text in the UI by
removing any mention of "response curve" from the p element with id
"statmodel_workflow_bullet_default" so it only references creating a contrast
matrix/group comparison; leave any response-curve wording confined to the p
element with id "statmodel_workflow_bullet_response_curve" and ensure this
change aligns with the behavior in statmodelServer() which removes
response-curve mode for non-turnover/non-chemoproteomics templates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 77ea17a6-6b49-483b-9ade-1ddf23f466d2

📥 Commits

Reviewing files that changed from the base of the PR and between 3162589 and 50c4d83.

📒 Files selected for processing (10)
  • DESCRIPTION
  • PREDESIGN.md
  • R/module-help-ui.R
  • R/module-loadpage-server.R
  • R/module-loadpage-ui.R
  • R/module-qc-ui.R
  • R/module-statmodel-server.R
  • R/statmodel-ui-comparisons.R
  • R/statmodel-ui-headers.R
  • man/MSstatsShiny.Rd
💤 Files with no reviewable changes (1)
  • man/MSstatsShiny.Rd

Comment thread DESCRIPTION Outdated
Comment thread R/module-loadpage-server.R
Comment thread R/module-loadpage-server.R
Comment thread R/module-qc-ui.R Outdated
Comment thread R/statmodel-ui-headers.R Outdated
@swaraj-neu swaraj-neu changed the title Merge Protein-turnover template followups into development Protein-turnover followups: MSstats-format CSV download, imputation help text, template-gated contrast UI Jun 2, 2026
Comment on lines +578 to +582
if (inherits(data, "data.frame")) {
paste0("MSstats_format-", Sys.Date(), ".csv")
} else {
paste0("MSstats_format-", Sys.Date(), ".zip")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'll always inherit data frame right?

Comment thread R/module-loadpage-server.R Outdated
Comment on lines +589 to +601
tmp_dir <- tempfile("msstats_format_")
dir.create(tmp_dir)
on.exit(unlink(tmp_dir, recursive = TRUE), add = TRUE)
tmp_files <- character()
for (nm in names(data)) {
tbl <- data[[nm]]
if (is.null(tbl)) next
if (NROW(tbl) == 0L) next
tmp_path <- file.path(tmp_dir, paste0(nm, ".csv"))
data.table::fwrite(tbl, tmp_path)
tmp_files <- c(tmp_files, tmp_path)
}
utils::zip(zipfile = file, files = tmp_files, flags = "-j")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simiilarly here, it should always inherit a data.frame. Or at least convertible into a data.table?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tonywu1999 Replying for both comment 1 and comment 2:
get_data() is a single data.frame for every converter except PTM. For PTM it's a list of two tables, PTM and PROTEIN, which this module already reads as get_data()$PTM and get_data()$PROTEIN (a data.frame's $ returns a column, not a full table). That list is what broke the original handler: fwrite produced a PTM,PROTEIN-headed CSV with columns collapsed by |. Since inherits(data, "data.frame") is FALSE for it, PTM now routes to the zip branch. Verified on a Metamorpheus PTM dataset, the download produces a valid zip with PTM.csv and PROTEIN.csv. The two are separate MSstats inputs (modified peptides vs unmodified proteins), so they can't be flattened into one CSV. Happy to just disable the button for PTM instead if you'd prefer the smaller surface.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's a great callout, in this case, that should be fine.

Comment thread DESCRIPTION Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@R/module-loadpage-server.R`:
- Around line 593-601: The tmp_files vector may be empty if every element in
data is NULL or has zero rows, causing utils::zip(zipfile = file, files =
tmp_files, ...) to fail; before calling utils::zip in the block that builds
tmp_files (the for loop over names(data) and the subsequent utils::zip call),
check if length(tmp_files) == 0 (or identical(tmp_files, character(0))) and if
so call stop() with a clear message (e.g. "No tables available to write to ZIP")
so the error is handled instead of invoking utils::zip with no files; ensure
this check is placed just before the utils::zip(...) invocation that uses the
variable file and tmp_files.
- Around line 584-603: The downloadHandler content function should be wrapped in
tryCatch to prevent unhandled errors from crashing the Shiny session: wrap the
entire body of the existing content = function(file) { ... } in tryCatch({...},
error = function(e) { write a short error message containing conditionMessage(e)
to the target file (use writeLines or writeBin depending on zip vs csv) instead
of calling stop(), and return silently }); ensure the existing cleanup
(on.exit(unlink(...))) and tmp_files handling remain intact and that failures in
data.table::fwrite, dir.create, or utils::zip are caught and result in an error
file for the user rather than rethrowing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 458ad809-a11c-481b-b0c2-f595bc3853b1

📥 Commits

Reviewing files that changed from the base of the PR and between 50c4d83 and d35c116.

📒 Files selected for processing (3)
  • R/module-loadpage-server.R
  • R/module-qc-ui.R
  • R/statmodel-ui-headers.R
✅ Files skipped from review due to trivial changes (1)
  • R/module-qc-ui.R
🚧 Files skipped from review as they are similar to previous changes (1)
  • R/statmodel-ui-headers.R

Comment thread R/module-loadpage-server.R
Comment thread R/module-loadpage-server.R Outdated
@tonywu1999 tonywu1999 merged commit 3ae58ae into devel Jun 3, 2026
2 checks passed
@tonywu1999 tonywu1999 deleted the MSstatsShiny/work/20260528_protein_turnover_easy_followups branch June 3, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants