Skip to content

feat: v12 UX Polish & Onboarding (#150, #87, #60, #9)#156

Merged
seanthimons merged 1 commit intointegrationfrom
v12-ux-polish-onboarding
Mar 20, 2026
Merged

feat: v12 UX Polish & Onboarding (#150, #87, #60, #9)#156
seanthimons merged 1 commit intointegrationfrom
v12-ux-polish-onboarding

Conversation

@seanthimons
Copy link
Copy Markdown
Owner

Summary

Testing

  • Smoke tested app startup — no errors
  • All acceptance criteria from the plan verified and checked off

Closes #150, closes #87, closes #60, closes #9

Copilot AI review requested due to automatic review settings March 13, 2026 21:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR delivers V12 UX polish across the Shiny app: onboarding/welcome workflow, better feedback for long-running synthesis actions, prompt transparency UI, version surfacing, and a verbose OpenAlex logging toggle—plus dark-mode styling updates to support the new UI elements.

Changes:

  • Reworked welcome modal + welcome landing page into a 5-step workflow, added contextual “info” text on key sidebar views.
  • Added synthesis progress modals/status text and introduced (partial) prompt editor UI for chat/presets.
  • Added SERAPEUM_VERSION and surfaced it in the title bar + About page; added optional OpenAlex verbose logging hook + dark-mode CSS updates.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
docs/plans/2026-03-13-feat-v12-ux-polish-onboarding-plan.md New implementation plan documenting V12 scope and acceptance criteria
docs/brainstorms/2026-03-13-v12-ux-polish-onboarding-brainstorm.md New brainstorm doc capturing decisions and rationale
app.R Version in window/title, welcome wizard + landing page overhaul, JS handlers (wizard + console logging)
R/theme_catppuccin.R Dark-mode CSS overrides for modals, prompt editor, version badge
R/rag.R Added preset-instruction helper + generate_preset() support for custom_prompt
R/mod_topic_explorer.R Added contextual help text at top of UI
R/mod_settings.R Added “Verbose API logging” toggle + persistence via DB setting + R option
R/mod_seed_discovery.R Added contextual help text at top of UI
R/mod_search_notebook.R Added contextual help text, prompt editor UI, synthesis modal/status plumbing
R/mod_query_builder.R Added contextual help text at top of UI
R/mod_document_notebook.R Added contextual help text, synthesis modal/status updates, prompt editor wiring (partial)
R/mod_citation_network.R Added contextual help text at top of UI
R/mod_citation_audit.R Added contextual help text at top of UI
R/mod_about.R Added “What’s New” section using SERAPEUM_VERSION
R/config.R Added SERAPEUM_VERSION constant
R/api_openalex.R Wrapped OpenAlex requests in perform_openalex() with optional verbose logging

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

observeEvent(input$wizard_analyze, {
removeModal()
current_notebook(NULL)
current_view("query_builder")
Comment on lines +666 to 673
# Show wizard on first load — only if no notebooks exist and not previously dismissed
observe({
con <- con_r()
req(con)
notebooks <- list_notebooks(con)
if (nrow(notebooks) == 0) {
has_seen <- isTRUE(input$has_seen_wizard)
if (nrow(notebooks) == 0 && !has_seen) {
shiny::onFlushed(function() {
R/mod_settings.R Outdated
"Changes only apply to newly uploaded documents."),
bslib::input_switch(ns("verbose_mode"), "Verbose API logging", value = FALSE),
p(class = "text-muted small",
"Log OpenAlex API calls to the browser console for debugging."),
Comment on lines +420 to +433
# Collapsible prompt editor (opt-in)
tags$details(
class = "mb-2",
tags$summary(class = "text-muted small", style = "cursor: pointer;",
icon_edit(), " View/Edit Prompt"),
div(
class = "border rounded p-2 mt-1",
textAreaInput(ns("prompt_edit"), NULL,
placeholder = "The assembled prompt will appear here when you type a message or click a preset...",
rows = 4, width = "100%"),
p(class = "text-muted small mb-0",
"Edit the prompt text before sending. Collapse this section to use the default prompts.")
)
),
Comment on lines +501 to +506
update_synthesis_status <- function(message) {
session$sendCustomMessage("updateSynthesisStatus", list(
msg_id = ns("synthesis_status"),
message = message
))
}
app.R Outdated
Comment on lines +159 to +163
// Verbose API logging to browser console
Shiny.addCustomMessageHandler('consoleLog', function(data) {
console.log('[' + data.label + ']', data.url);
});

Comment on lines +8 to +12
#' @return httr2 response
perform_openalex <- function(req) {
if (isTRUE(getOption("serapeum.verbose_api", FALSE))) {
url <- req$url
message("[OpenAlex API] ", url)
Comment on lines 3297 to 3310
observeEvent(input$btn_overview_generate, {
req(!is_processing())
req(has_api_key())
is_processing(TRUE)

depth <- input$overview_depth %||% "concise"
mode <- input$overview_mode %||% "quick"

depth_label <- if (identical(depth, "detailed")) "Detailed" else "Concise"
mode_label <- if (identical(mode, "thorough")) "Thorough" else "Quick"

toggle_popover(id = ns("overview_popover"))
show_synthesis_modal(paste0("Overview (", depth_label, ", ", mode_label, ")"))

Comment on lines +962 to +981
# If prompt editor is expanded and empty, populate it with the system prompt
# and wait for the user to review/edit before sending
edited_prompt <- trimws(input$prompt_edit %||% "")
editor_open <- isTRUE(input$prompt_editor_open)
if (editor_open && nchar(edited_prompt) == 0) {
rag_system <- "You are a helpful research assistant. Answer questions based ONLY on the provided sources. Always cite your sources using the format [Document Name, p.X] or [Paper Title]."
assembled <- paste0("[System Prompt]\n", rag_system, "\n\n[Your Question]\n", user_msg)
session$sendCustomMessage("populatePromptEditor", list(
input_id = ns("prompt_edit"),
text = assembled
))
showNotification("Prompt loaded into editor. Edit and click Send when ready.",
type = "message", duration = 3)
# Re-enable the send button (it was disabled by the click handler JS)
session$sendCustomMessage("docChatReady", ns(""))
return()
}

effective_msg <- if (nchar(edited_prompt) > 0) edited_prompt else user_msg

Comment on lines 901 to +907
if (is_processing()) {
doc_count <- tryCatch(nrow(list_documents(con(), notebook_id())), error = function(e) 0L)
status_text <- if (doc_count > 0) {
sprintf("Analyzing %d document%s...", doc_count, if (doc_count == 1) "" else "s")
} else {
"Thinking..."
}
@seanthimons seanthimons changed the title feat: V12 UX Polish & Onboarding (#150, #87, #60, #9) feat: v12 UX Polish & Onboarding (#150, #87, #60, #9) Mar 19, 2026
seanthimons added a commit that referenced this pull request Mar 19, 2026
- Fix wizard_analyze label/route mismatch (button now says "Query Builder")
- Fix verbose logging text ("browser console" → "R console") and remove dead consoleLog JS handler
- Move updateSynthesisStatus JS handler to global scope in app.R
- Add empty notebook guard to search notebook overview preset
- Cache doc_count in reactiveVal to avoid repeated DB queries during render
- Strip half-baked prompt editor UI and server logic (tracked in #164)
@seanthimons seanthimons requested a review from Copilot March 19, 2026 16:37
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR targets the v12 UX/onboarding polish set: improving first-run guidance, adding progress feedback for long-running synthesis actions, introducing app version surfacing, adding contextual sidebar help text, and adding a verbose OpenAlex logging toggle.

Changes:

  • Reworks the welcome wizard + welcome landing view into a 5-step workflow with routing actions.
  • Adds synthesis progress modals + more contextual “Thinking…” status text in notebook chat UIs, plus empty-notebook guards for some presets.
  • Adds version constant + title-bar badge and an About “What’s New” section; adds a Settings toggle + OpenAlex request wrapper for verbose logging.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
docs/plans/2026-03-13-feat-v12-ux-polish-onboarding-plan.md Adds the implementation plan for v12 UX/onboarding scope.
docs/brainstorms/2026-03-13-v12-ux-polish-onboarding-brainstorm.md Captures feature brainstorming/decisions for the v12 scope.
app.R Adds version in title/tab, welcome wizard + landing workflow, and a global JS handler for synthesis status updates.
README.md Updates feature list to mention onboarding, progress feedback, verbose logging, and prompt editing.
R/theme_catppuccin.R Adds dark-mode CSS overrides for modals, prompt-editor styling, and version badge.
R/rag.R Adds preset instruction helper and custom_prompt support in generate_preset().
R/mod_settings.R Adds “Verbose API logging” switch and persists it to DB; sets a global R option.
R/api_openalex.R Introduces perform_openalex() wrapper and routes OpenAlex calls through it.
R/mod_document_notebook.R Adds contextual help text, synthesis modal + inline status improvements, and empty-notebook guards for presets.
R/mod_search_notebook.R Adds contextual help text, synthesis modal helpers, inline status improvements, and an empty-notebook guard for Overview.
R/mod_seed_discovery.R Adds contextual help text on landing state.
R/mod_query_builder.R Adds contextual help text on landing state.
R/mod_topic_explorer.R Adds contextual help text on landing state.
R/mod_citation_network.R Adds contextual help text on landing state.
R/mod_citation_audit.R Adds contextual help text on landing state.
R/mod_about.R Adds “What’s New” section referencing SERAPEUM_VERSION.
R/config.R Adds SERAPEUM_VERSION constant.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +687 to 691
observeEvent(input$wizard_search, {
removeModal()
current_notebook(NULL)
current_view("discover")
})
Comment on lines +9 to +12
perform_openalex <- function(req) {
if (isTRUE(getOption("serapeum.verbose_api", FALSE))) {
url <- req$url
message("[OpenAlex API] ", url)
R/rag.R Outdated
Comment on lines +138 to +165
prompt <- presets[[preset_type]]
generate_preset <- function(con, config, notebook_id, preset_type, session_id = NULL,
custom_prompt = NULL) {
prompt <- custom_prompt %||% get_preset_instruction(preset_type)
Comment on lines 3390 to 3394
req(!is_processing())
req(has_api_key())
is_processing(TRUE)
show_synthesis_modal("Research Questions")

Comment on lines +575 to +578
observeEvent(input$welcome_search, {
current_notebook(NULL)
current_view("discover")
})
Comment on lines +667 to 678
# Show wizard on first load — only if no notebooks exist and not previously dismissed
observe({
con <- con_r()
req(con)
notebooks <- list_notebooks(con)
if (nrow(notebooks) == 0) {
has_seen <- isTRUE(input$has_seen_wizard)
if (nrow(notebooks) == 0 && !has_seen) {
shiny::onFlushed(function() {
showModal(wizard_modal())
}, once = TRUE)
}
}) |> bindEvent(con_r(), once = TRUE)
R/mod_settings.R Outdated
updateNumericInput(session, "chunk_overlap", value = chunk_overlap)

verbose_mode <- get_db_setting(con(), "verbose_mode") %||% FALSE
bslib::update_switch("verbose_mode", value = isTRUE(verbose_mode))
Comment on lines 18 to 21
- **One-click presets** - Summarize, Key Points, Study Guide, Outline, and more
- **Synthesis progress feedback** - Status modal with rotating stage indicators for long-running presets
- **Editable prompts** - Expand the prompt editor to view and customize LLM prompts before sending
- **Chat export** - Download conversations as Markdown (.md) or styled HTML (.html)
Comment on lines 3352 to 3356
req(!is_processing())
req(has_api_key())
is_processing(TRUE)
show_synthesis_modal("Conclusion Synthesis")

seanthimons added a commit that referenced this pull request Mar 19, 2026
- Add empty notebook guards to search notebook Conclusions and Research
  Questions presets (prevents modal flash on empty notebooks)
- Redact api_key from verbose OpenAlex log output
- Fix wizard dismissal race by requiring has_seen_wizard input before check
- Fix misplaced roxygen docs on generate_preset() and document custom_prompt
- Remove "Editable prompts" from README (feature not yet implemented)
Without the session parameter, the verbose API logging toggle
may not restore correctly from saved settings on app startup.
@seanthimons seanthimons changed the base branch from main to integration March 20, 2026 17:21
@seanthimons seanthimons merged commit a40025e into integration Mar 20, 2026
1 check passed
@seanthimons seanthimons deleted the v12-ux-polish-onboarding branch March 22, 2026 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants