Refactor: Add Shiny web app, dual authentication, multi-domain support, and improve code organization#1
Open
PMichaels-SC wants to merge 36 commits intomainfrom
Open
Refactor: Add Shiny web app, dual authentication, multi-domain support, and improve code organization#1PMichaels-SC wants to merge 36 commits intomainfrom
PMichaels-SC wants to merge 36 commits intomainfrom
Conversation
Changes: - Update get_dataframe.R and results_analysis.R to load credentials from .Renviron - Add interactive prompting for analysis keys (changes per run) - Fix subdomain parsing bug that doubled .benchling.com suffix - Add better error handling and progress indicators - Create .Renviron.example template for credential configuration - Add Shiny web app (app.R) as alternative interface - Add test_ic50_locally.R for testing without Benchling credentials - Create comprehensive documentation (CLAUDE.md, SETUP_GUIDE.md) - Add .gitignore to protect credentials and output files - Initialize renv for dependency management Benefits: - Credentials no longer hardcoded in scripts (security improvement) - Analysis keys prompted at runtime (more flexible workflow) - Both command-line and web UI options available - Better documentation for setup and troubleshooting
This file contains project-specific Claude Code instructions and should not be tracked in the repository.
Changes: - Create utils.R with shared IC50 calculation and plotting functions - Reduce code duplication by ~200 lines across main scripts - Update test_ic50_locally.R to use utilities (128 → 85 lines, -34%) - Update results_analysis.R to use utilities (404 → ~340 lines, -16%) - Update app.R to use utilities (337 → ~290 lines, -14%) New examples directory: - examples/README.md - Learning path guide with 4 progressive tutorials - examples/example_1_local_test.R - IC50 basics (no API needed) - examples/example_2_fetch_data.R - Authentication & data fetching - examples/example_3_full_workflow.R - Complete pipeline walkthrough - examples/example_4_shiny_app.R - Shiny web UI patterns Documentation: - Update README.md with learning path section - Update CLAUDE.md with utilities and examples documentation Benefits: - Eliminates duplicate IC50/plotting code - Maintains educational clarity (API patterns still visible) - Provides progressive learning structure - Fully backward compatible with existing scripts - Better organized for new learners
Removed: - test_ic50_locally.R (redundant with examples/example_1_local_test.R) - Generated output files (*.html, *.csv from script runs) Updated: - .gitignore to exclude future generated files from examples/ - README.md to remove references to test_ic50_locally.R - CLAUDE.md to note that example_1 replaces test_ic50_locally.R Rationale: - For an educational repo, example_1_local_test.R is better (more verbose, better documented) - Generated files shouldn't be committed to git - Reduces confusion by having one clear starting point
Consolidated examples directory to focus on essential local testing: - Removed example_1-4 files (overly complex for educational repo) - Kept single local_test.R demonstrating IC50 calculation offline - Renamed Mortality IC50.csv → examples/sample_ic50_data.csv (clearer purpose) - Merged examples/README.md into root README (single source of documentation) Updated terminology and dependencies: - Changed "Production Usage" → "Full Workflow" (better for educational context) - Added htmlwidgets to renv.lock (required for local_test.R plot export) - Updated .gitignore for new file structure and output patterns The examples directory is now self-contained with clear input/output separation.
Merged SETUP_GUIDE.md into README.md as an expandable section: - Quick setup steps remain at top for fast reference - Detailed instructions available in collapsible <details> section - Preserves all setup guidance (app creation, credentials, troubleshooting) - Single source of truth for documentation Benefits: - Easier to maintain (one file vs two) - Better discoverability (everything in README) - Still scannable (quick setup at top, details expanded on demand)
MAJOR SIMPLIFICATION: Analysis keys contain JWT tokens that work as bearer tokens, eliminating need for separate Benchling App credentials! Changes: - get_dataframe.R: Extract JWT from analysis key, use directly (removed OAuth2) - app.R: Same simplification for Shiny app - .Renviron.example: Now optional, only for automation - README.md: Removed Benchling App setup steps from quick start - CLAUDE.md: Updated architecture docs to reflect JWT-only auth Benefits: ✅ No Benchling App creation needed ✅ No client_id/client_secret management ✅ No OAuth2 token generation ✅ ~130 lines of code/docs removed ✅ Simpler setup (3 steps instead of 6) ✅ Lower barrier to entry for learners Test script (test_analysis_key_auth.R) included for reference - this is how we discovered the JWT tokens work directly as bearer tokens. Analysis key format: ana_XXXXX:JWT_TOKEN (JWT after colon is the bearer token)
Since authentication now uses only the analysis key JWT, there's no need for a .Renviron template file. Users can optionally create .Renviron for automation, but it's not required for the workflow. Simplified setup: just run the script and paste your analysis key when prompted.
The test file served its purpose (discovering JWT auth works), but now that the refactor is complete, it's just maintenance overhead. Added TODO in CLAUDE.md to investigate whether Benchling Apps Guide link is still relevant in documentation.
…native Added comprehensive documentation and code artifacts for both authentication methods: JWT (Analysis Key) - DEFAULT: - Simple, user-attributable, 10-minute expiration - Best for: learning, demos, quick workflows - Active implementation in get_dataframe.R and app.R OAuth2 (Benchling App) - ALTERNATIVE: - Permanent credentials, app-attributable - Best for: production, long-running workflows (>10 min) - Fully documented in commented code blocks Changes: - get_dataframe.R: Added auth comparison header, OAuth2 template (lines 108-167) - app.R: Added auth guidance comments - README.md: New "Authentication Methods" section with tradeoffs - CLAUDE.md: New "Authentication Architecture" section with implementation details - .Renviron.example: Recreated with clear guidance for both approaches Key insights documented: - JWT tokens expire after 10 minutes (not 15) - User vs app attribution implications - When to choose each approach - How to switch between them This provides educational value while supporting real-world use cases.
Added explicit note that analysis key format is analysis_id:JWT_token with colon delimiter, and that the JWT portion is used as the bearer token.
Specified exact UI steps: click 'Connect with external tool' then 'Copy Analysis Key' in the popup. Added to both Quick Setup and detailed instructions sections.
Added explicit step to upload examples/sample_ic50_data.csv to the analysis. Noted that in production usage, this would be an existing dataset or results table from experiments. Updated both Quick Setup and detailed instructions.
Added START/END markers around authentication sections to make it obvious which code blocks to comment/uncomment when switching approaches: get_dataframe.R: - ### START: JWT AUTHENTICATION (Comment out this entire section if using OAuth2) ### - ### END: JWT AUTHENTICATION ### - ### START: OAUTH2 AUTHENTICATION (Uncomment this entire section if using OAuth2) ### - ### END: OAUTH2 AUTHENTICATION ### app.R: - Similar markers around JWT sections - Reference to get_dataframe.R lines for OAuth2 pattern Makes it much easier for users to switch between authentication methods.
Replaced comment/uncomment blocks with a single flag at top of file: - USE_OAUTH2 <- FALSE (default, JWT authentication) - USE_OAUTH2 <- TRUE (OAuth2 with app credentials) Benefits: - Much simpler switching - just change one line - Same UX for both methods (paste full analysis key) - Clear configuration section at top - OAuth2 credentials only loaded when needed Also: - Added Shiny packages to renv.lock (shiny, shinythemes, shinycssloaders) - Updated CLAUDE.md with current line references (gitignored) - Confirmed README already shows correct shiny::runApp() usage
Replaced comment/uncomment blocks with a single flag (matching app.R pattern): - USE_OAUTH2 <- FALSE (default, JWT authentication) - USE_OAUTH2 <- TRUE (OAuth2 with app credentials) Benefits: - Much simpler switching - just change line 12 - Same UX for both methods (paste full analysis key) - Clear configuration section at top - OAuth2 credentials only loaded when needed - if/else logic instead of commented code blocks Now both get_dataframe.R and app.R use the same simple flag-based switching.
Changed documentation from 'commented code blocks' to 'USE_OAUTH2 flag' to match the new simplified authentication switching mechanism in both get_dataframe.R and app.R.
Changed IC50_result (undefined) to result (correct variable from line 54). Also changed result$value to result$ic50 to match the actual return value from calculate_ic50() utility function.
Updated sample_ic50_data.csv to use standard column names: - Concentration → Cell.Mortality.Concentration - Mortality 24h → Cell.Mortality.Mortality.24h - Mortality 48h → Cell.Mortality.Mortality.48h Benefits: - Sample data now matches format expected by main workflow - No column renaming needed in local_test.R - More uniform and realistic (matches actual Benchling data format) - Simpler for users to understand Updated files: - examples/sample_ic50_data.csv: New standardized column names - examples/local_test.R: Removed column renaming, updated references - utils.R: Updated example code to match new column names
Extended results_analysis.R and local_test.R to calculate and visualize IC50 for both 24h and 48h timepoints, matching the functionality in app.R. Changes: - results_analysis.R: Calculate IC50 for both 24h and 48h, create two plots, upload both to Benchling, include both in results CSV - local_test.R: Calculate IC50 for both timepoints, generate two interactive HTML plots for local testing This provides a complete dose-response analysis across timepoints for better understanding of compound potency over time.
Changed results_analysis.R to create temporary files (CSV and HTML plots) in a tmp/ directory instead of the project root. Files are automatically cleaned up after successful upload to Benchling. Changes: - Create tmp/ directory at start of script - Save all temporary files (mortality.csv, plots) to tmp/ - Clean up files after successful upload - Remove tmp/ directory if empty after cleanup - Updated .gitignore to ignore tmp/ directory This keeps the project root clean and makes it clear which files are temporary versus permanent.
Changed add_lines() to add_trace() with explicit mode='lines' to ensure the fitted curve displays as a line only, while observed data points retain their markers.
Switched to add_lines() which is specifically designed for line-only traces in plotly, avoiding any marker display issues.
Using add_trace() with mode='lines', marker size=0, and inherit=FALSE to ensure the fitted curve displays as a line only without markers.
…g, etc.) Fixed domain parsing to handle both production and development Benchling environments. The code now correctly handles: - Full domains: tenant.benchling.com, tenant.bnchdev.org - Subdomains only: tenant (automatically appends .benchling.com) Changes: - get_dataframe.R: Extract and use full domain from JWT/OAuth2 credentials - results_analysis.R: Use base_domain instead of constructing URLs - app.R: Create base_domain reactive, update all URL constructions This fixes the issue where dev environments (*.bnchdev.org) were being incorrectly converted to *.bnchdev.org.benchling.com.
Updated documentation to always require full domain (tenant.benchling.com or tenant.bnchdev.org) for BENCHLING_TENANT_SUBDOMAIN. This is clearer than allowing just 'tenant' since users may not be aware of all possible domain suffixes. Examples now show only full domain format.
…ENANT_SUBDOMAIN Renamed environment variable from BENCHLING_TENANT_SUBDOMAIN to BENCHLING_DOMAIN for clarity. Now OAuth2 setup simply requires: BENCHLING_DOMAIN=your_tenant.benchling.com Changes: - .Renviron.example: Updated to use BENCHLING_DOMAIN, removed dev examples - get_dataframe.R: Read from BENCHLING_DOMAIN, simplified domain logic - app.R: Read from BENCHLING_DOMAIN, simplified token URL generation Users with dev domains will know to substitute their domain (e.g., tenant.bnchdev.org).
Updated sample data and all scripts to use simpler column names: - Cell (was: Cell.Line.Name) - Concentration (was: Cell.Mortality.Concentration) - Mortality 24h (was: Cell.Mortality.Mortality.24h) - Mortality 48h (was: Cell.Mortality.Mortality.48h) Changes: - examples/sample_ic50_data.csv: Added Cell column (CHO-B-002), simplified column names - examples/local_test.R: Updated to use new column names, extract cell name from data - results_analysis.R: Updated to use new column names, extract cell name from Cell column - app.R: Updated column patterns to match new names, extract cell name from data Results dataframes now use actual cell names from the Cell column instead of hardcoded "Cell Line" or "Unknown" values.
R's read.csv() automatically converts spaces to dots in column names.
Changed all scripts to use 'Mortality.24h' and 'Mortality.48h' instead
of 'Mortality 24h' and 'Mortality 48h'.
Changes:
- examples/local_test.R: Use Mortality.24h and Mortality.48h
- results_analysis.R: Use Mortality.24h and Mortality.48h
- app.R: Simplified regex to match Mortality.24h format
CSV file still uses spaces ('Mortality 24h') which is more readable,
but R converts them to dots when reading.
Changed column header from 'Cell' to 'Cell Name' for better clarity. Changes: - examples/sample_ic50_data.csv: Renamed 'Cell' to 'Cell Name' - examples/local_test.R: Updated references from df$Cell to df$Cell.Name - results_analysis.R: Updated required_cols and cell line extraction to use Cell.Name - app.R: Updated cell name extraction to use df$Cell.Name Note: R converts 'Cell Name' (space) to 'Cell.Name' (dot) when reading CSV.
Removed the problematic 'marker = list(size = 0)' configuration from the fitted curve trace. This was causing plotly to add markers even with size=0. The plot now correctly shows: - Observed data points: Blue dots (markers only) - Fitted curve: Red line (no markers) This eliminates the warning 'A marker object has been specified, but markers is not in the mode' and removes the unwanted orange markers on the fitted line.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR significantly improves the repository's usability and maintainability by adding a Shiny web interface, flexible authentication
options, supporting multiple Benchling environments, and extracting common code into utilities.
Key Changes
🚀 Shiny Web Application
app.R) for IC50 analysis workflow🔐 Authentication Improvements
.Renvironfor OAuth2🌐 Multi-Domain Support
.benchling.com) and development (.bnchdev.org) environments📦 Code Organization
utils.R:calculate_ic50(): Standardized IC50 calculationcreate_ic50_plot(): Consistent plot generationexamples/local_test.R) that works without Benchling credentials🎨 UI/UX Improvements
Cell.Mortality.ConcentrationtoConcentration📚 Documentation Updates
.Renviron.examplewith clear setup instructionsBreaking Changes
Cell Name,Concentration,Mortality 24h,Mortality 48h)Testing
.bnchdev.orgUsage
Command Line: