Skip to content

refactor(statsmodel): Refactor statsmodel UI components to be more readable#117

Merged
tonywu1999 merged 6 commits intodevelfrom
feat-dose-response
Oct 31, 2025
Merged

refactor(statsmodel): Refactor statsmodel UI components to be more readable#117
tonywu1999 merged 6 commits intodevelfrom
feat-dose-response

Conversation

@tonywu1999
Copy link
Copy Markdown
Contributor

@tonywu1999 tonywu1999 commented Oct 31, 2025

Why

Statmodule UI needs to be refactored so that new developers can easily add the new dose response curve feature.

Changes

  • Refactored stat-module-UI file to have separate helper methods and split helper methods into appropriate folders.

Testing

  • Added unit tests and verified all unit tests passed before and after the changes.
  • Verified locally that nothing breaks for basic functionality.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Oct 31, 2025

Walkthrough

Refactors a monolithic Shiny UI into modular, namespaced builder functions, adds UI helper modules for headers/styles, splits contrast/modeling/visualization/results into separate builders, adds comprehensive UI tests, and bumps RoxygenNote in DESCRIPTION. Minor text punctuation edits in sample dataset descriptions.

Changes

Cohort / File(s) Summary
Metadata Update
\DESCRIPTION``
RoxygenNote version bump from 7.3.2 to 7.3.3
Main Module Refactoring
\R/module-statmodel-ui.R``
Replaces inline UI construction with calls to modular builders: create_custom_styles(), create_header_section(), create_contrast_section(), create_modeling_section(), create_visualization_section(), create_results_section()
Header & Style Utilities
\R/statmodel-ui-headers.R``
Adds create_custom_styles() (button styling, stylesheet link) and create_header_section() (title, description, doc link)
Contrast Options UI
\R/statmodel-ui-options-contrasts.R``
Adds contrast UI builders: create_contrast_section(), create_contrast_radio_buttons(), create_custom_pairwise_panel(), create_all_vs_one_panel(), create_all_pairwise_panel(), create_custom_nonpairwise_panel() with conditional panels
Modeling Options UI
\R/statmodel-ui-options-modeling.R``
Adds modeling UI builders: create_modeling_section(), create_moderation_option(), create_significance_slider()
Visualization Options UI
\R/statmodel-ui-options-visualization.R``
Adds visualization UI builders: create_visualization_section(), create_plot_type_selector(), create_volcano_plot_options(), create_comparison_plot_options(), create_heatmap_options(), create_fold_change_options(), create_plot_action_buttons() with plot-type conditional logic
Results Section UI
\R/statmodel-ui-results.R``
Adds create_results_section() and create_results_tables() with PTM / non-PTM conditional rendering and tabbed PTM outputs
UI Component Tests
\tests/testthat/test-module-statmodel-ui.R``
Adds extensive tests validating UI structure, ordering, namespace prefixes, conditional panels, controls, buttons, tooltips, placeholders, and PTM tab structure
Minor Text Edits
\R/module-loadpage-ui.R``
Adjusts sample dataset description punctuation/spelling (en dash → hyphen/space) only

Sequence Diagram(s)

sequenceDiagram
    participant App as statmodelUI
    participant Headers as create_custom_styles / create_header_section
    participant Contrasts as create_contrast_section
    participant Modeling as create_modeling_section
    participant Viz as create_visualization_section
    participant Results as create_results_section
    participant User as User (browser)

    rect rgb(240,248,255)
    App ->> Headers: call to assemble header/styles
    App ->> Contrasts: call to build contrast UI (namespaced)
    App ->> Modeling: call to build modeling UI (namespaced)
    App ->> Viz: call to build visualization UI (namespaced)
    App ->> Results: call to build results UI (namespaced)
    end

    Note right of App: UI composed of modular sections\nreturned as tagLists / UI elements

    User ->> Contrasts: select contrast radio -> conditional panel toggles
    User ->> Modeling: toggle moderation / adjust significance slider
    User ->> Viz: choose plot type -> conditional plot options appear
    User ->> Results: view results / tabs render based on PTM flag
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas to focus:
    • Namespace correctness across builder functions and IDs.
    • ConditionalPanel expressions and linked input IDs (contrast and plot-type logic).
    • Tests: ensure selectors used in tests match namespaced IDs and conditional visibility expectations.

Possibly related PRs

Suggested labels

Review effort 3/5

Poem

🐇 I hopped through code with tidy paws and cheer,

Split the big UI into parts so clear.
Headers, contrasts, plots — each in its place,
Tests keep it steady, neat, and ace.
A carrot-sized bump to docs — hip, hooray!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "refactor(statsmodel): Refactor statsmodel UI components to be more readable" accurately reflects the primary objective and main changes in the changeset. The raw summary confirms that the dominant changes are the refactoring of R/module-statmodel-ui.R into separate modular builder functions and the creation of new UI helper files (statmodel-ui-headers.R, statmodel-ui-options-contrasts.R, statmodel-ui-options-modeling.R, statmodel-ui-options-visualization.R, statmodel-ui-results.R), along with comprehensive test coverage. The title is specific enough to convey the refactoring intent while remaining concise and clear, and it aligns with the stated PR objective of improving code readability to facilitate future feature development.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-dose-response

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.

@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (7)
R/statmodel-ui-headers.R (1)

7-22: Consider centralizing button IDs or using a data-driven approach.

The hardcoded button IDs in the style tags create coupling between this function and button definitions elsewhere. If button IDs change in the future, these styles will silently fail to apply.

Consider one of these approaches:

  • Define button IDs as constants in a shared location
  • Use CSS classes instead of IDs for styling
  • Generate styles dynamically based on a list of button IDs

Example refactor using a constant list:

+# Define button IDs as constants
+ORANGE_BUTTON_IDS <- c("submit3", "clear3", "submit1", "clear1", 
+                        "submit2", "clear2", "calculate", "plotresults", 
+                        "viewresults", "submit", "clear")
+
 create_custom_styles <- function() {
+  button_styles <- lapply(ORANGE_BUTTON_IDS, function(id) {
+    tags$style(HTML(sprintf('#statmodel-%s{background-color:orange}', id)))
+  })
   tags$head(
-    tags$style(HTML('#statmodel-submit3{background-color:orange}')),
-    tags$style(HTML('#statmodel-clear3{background-color:orange}')),
-    ...
+    button_styles,
     tags$link(rel = "stylesheet", type = "text/css", href = "assets/style.css")
   )
 }
R/statmodel-ui-options-visualization.R (3)

31-31: Remove commented-out code or track as an issue.

The commented-out "Response Curve" option suggests incomplete work. Either implement it now, remove the comment, or open an issue to track future work.

Do you want me to open a new issue to track the Response Curve feature implementation?


40-46: Hardcoded namespace breaks module isolation.

The conditionalPanel on lines 40-41 and 44 hardcodes the 'statmodel' namespace string. This creates tight coupling and prevents the module from being instantiated with different IDs. While this matches the current usage, it violates Shiny module best practices.

Shiny's conditionalPanel doesn't support dynamic namespacing easily, but you can document the limitation or consider using renderUI with conditionalPanel inside for better namespace handling. Alternatively, document that these functions are tightly coupled to the "statmodel" namespace.

Add a comment at the top of the file:

# Note: conditionalPanel conditions use hardcoded 'statmodel' namespace.
# These functions are tightly coupled to statmodelUI("statmodel") usage.

121-128: JavaScript boolean comparison uses string instead of boolean.

Line 122 compares against the string "true" instead of the boolean true. While this may work due to JavaScript's type coercion, it's better to use the correct type for clarity and to avoid potential issues.

Consider updating to:

     conditionalPanel(
-      condition = "input['statmodel-FC1'] == true",
+      condition = "input['statmodel-FC1']",
       numericInput(

Or if you need explicit comparison:

-      condition = "input['statmodel-FC1'] == true",
+      condition = "input['statmodel-FC1'] === true",
R/statmodel-ui-results.R (1)

18-21: Address or remove TODO comments.

Lines 18, 19, and 21 contain comments suggesting renames and feature additions. These indicate incomplete refactoring work.

Please either:

  1. Complete the suggested refactoring now
  2. Remove the comments if the current naming is final
  3. Create issues to track these future improvements

Do you want me to help generate updated code for these suggestions or open issues to track them?

R/statmodel-ui-options-modeling.R (1)

16-16: Remove or implement TODO comment.

The comment suggests adding dose response options but the feature isn't implemented. Either implement it now or track it separately.

Do you want me to open an issue to track the dose response curve feature?

R/statmodel-ui-options-contrasts.R (1)

16-16: Remove or implement TODO comment.

The comment about dose response curve mapping is one of several similar comments across the UI files. Consider consolidating these feature requests into a single tracked issue.

There are multiple dose response comments across files (Lines 16 in this file, line 16 in statmodel-ui-options-modeling.R, line 31 in statmodel-ui-options-visualization.R). Do you want me to help create a consolidated issue to track this feature?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3491ecd and 6573877.

📒 Files selected for processing (8)
  • DESCRIPTION (1 hunks)
  • R/module-statmodel-ui.R (1 hunks)
  • R/statmodel-ui-headers.R (1 hunks)
  • R/statmodel-ui-options-contrasts.R (1 hunks)
  • R/statmodel-ui-options-modeling.R (1 hunks)
  • R/statmodel-ui-options-visualization.R (1 hunks)
  • R/statmodel-ui-results.R (1 hunks)
  • tests/testthat/test-module-statmodel-ui.R (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
R/module-statmodel-ui.R (1)

14-35: Excellent refactoring to modular UI builders!

The refactored code is much more readable and maintainable. Breaking the monolithic UI into focused builder functions (create_contrast_section, create_modeling_section, create_visualization_section, create_results_section) makes the code easier to understand and test.

The modular approach provides clear separation of concerns and makes each UI section independently testable.

R/statmodel-ui-options-contrasts.R (1)

5-19: Well-structured contrast section builder.

The modular breakdown into radio buttons and conditional panels for each comparison type is clean and maintainable.

tests/testthat/test-module-statmodel-ui.R (1)

1-349: Comprehensive test coverage with excellent organization!

The test suite provides thorough coverage of the UI structure, including:

  • Component ordering and presence
  • Conditional panel logic
  • Button states and IDs
  • Input controls and options
  • Namespace consistency
  • Validation messages
  • Tabset structure

The organization into logical sections (1-11) makes the tests easy to navigate and maintain.

Note on test brittleness: The tests rely on HTML structure and specific encoding (e.g., &#39; for single quotes). While comprehensive, these tests may require updates if:

  • The htmltools package changes its HTML rendering
  • Shiny changes its HTML structure
  • HTML escaping behavior changes

Consider adding some higher-level functional tests using shinytest2 to complement these structural tests, which would be more robust to implementation changes.

Comment thread R/statmodel-ui-options-modeling.R
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
R/statmodel-ui-options-visualization.R (4)

70-76: Fix hardcoded namespace in conditionalPanel.

Line 72 has the same hardcoded namespace issue as flagged in the volcano plot options.


80-111: Fix hardcoded namespace and spelling errors.

Line 82 has the same hardcoded namespace issue flagged earlier.

Additionally, lines 105-107 contain spelling errors in user-facing text.

Apply this diff to fix the typo:

     c(
-      "protein dendogram" = "protein", 
-      "comparison dendogram" = "comparison", 
-      "protein and comparison dendograms" = "both"
+      "protein dendrogram" = "protein", 
+      "comparison dendrogram" = "comparison", 
+      "protein and comparison dendrograms" = "both"
     )

115-130: Fix hardcoded namespace in conditionalPanel.

Line 122 has the same hardcoded namespace issue flagged earlier.


134-146: Fix hardcoded namespace in conditionalPanel.

Line 138 has the same hardcoded namespace issue ("loadpage") flagged earlier. This cross-module dependency should be handled more robustly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6573877 and 393d5cc.

📒 Files selected for processing (3)
  • R/module-loadpage-ui.R (1 hunks)
  • R/statmodel-ui-options-modeling.R (1 hunks)
  • R/statmodel-ui-options-visualization.R (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • R/module-loadpage-ui.R
🚧 Files skipped from review as they are similar to previous changes (1)
  • R/statmodel-ui-options-modeling.R
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
R/statmodel-ui-options-visualization.R (2)

8-18: LGTM!

The composition is clean and follows a modular pattern for building the visualization section.


22-35: LGTM!

The plot type selector is well-structured, and the comment on line 31 clearly documents the planned dose response feature.

Comment on lines +39 to +66
create_volcano_plot_options <- function(ns) {
conditionalPanel(
condition = "input['statmodel-typeplot'] == 'VolcanoPlot'",
uiOutput(ns("WhichComp")),
conditionalPanel(
condition = "input['loadpage-DDA_DIA']!=='TMT'",
checkboxInput(ns("pname"), label = p("display protein name"))
),
selectInput(
ns("logp"),
label = h5("Log transformation of adjusted p-value"),
c("base 2" = "2", "base 10" = "10"),
selected = "10"
),
sliderInput(
ns("sig"),
label = h5(
"Adjusted p-value cutoff",
class = "icon-wrapper",
icon("question-circle", lib = "font-awesome"),
div("The cutoff used to determine significant results.", class = "icon-tooltip")
),
0, 1, 0.05
),
create_fold_change_options(ns),
tags$br()
)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix hardcoded namespace in conditionalPanel conditions.

Lines 41 and 44 use hardcoded namespace strings ("statmodel" and "loadpage") in conditionalPanel conditions, which breaks modularity and will cause runtime failures if this module is ever instantiated with a different namespace. This is inconsistent with the parameterized ns() approach used for input IDs.

The proper pattern for dynamic namespace evaluation in conditionalPanel requires either:

  1. Using JavaScript-based namespace construction
  2. Passing the namespace as a data attribute and referencing it in the condition

Since Shiny's conditionalPanel uses JavaScript for the condition, you'll need to ensure the namespace matches. Consider one of these approaches:

Option 1: Use ns() wrapper in the condition (requires NS to be available in client-side JavaScript):

  conditionalPanel(
-   condition = "input['statmodel-typeplot'] == 'VolcanoPlot'",
+   condition = sprintf("input['%s'] == 'VolcanoPlot'", ns("typeplot")),

Option 2: Document the namespace dependency and verify it matches the module's actual namespace ("statmodel"). If this is always used within the same fixed module, add a comment explaining the constraint.

Note: Line 59's tooltip text appears correctly fixed from the previous review.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
R/statmodel-ui-options-visualization.R around lines 39 to 66: the
conditionalPanel conditions on lines 41 and 44 use hardcoded IDs
("statmodel-typeplot" and "loadpage-DDA_DIA") which breaks module namespacing;
replace those hardcoded strings by constructing the JS condition with the module
namespace at render time (e.g. build the condition string using ns(...) and
sprintf/paste0 so the resulting condition references input['<namespaced-id>']
rather than a fixed prefix), updating both conditionalPanel calls accordingly
(or, if the module truly requires a fixed parent namespace, add a clear comment
documenting that constraint).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant