From c36b0327d7244bb260f3e830d5c935335c7fa274 Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Wed, 17 Dec 2025 15:25:48 -0500 Subject: [PATCH 1/2] refactor: Allow directly providing `id` --- pkg-r/R/QueryChat.R | 39 ++++++++++++++++++++------------------- pkg-r/man/QueryChat.Rd | 17 ++++++++++++++--- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/pkg-r/R/QueryChat.R b/pkg-r/R/QueryChat.R index fe4a2f9f0..ba1218fd3 100644 --- a/pkg-r/R/QueryChat.R +++ b/pkg-r/R/QueryChat.R @@ -512,8 +512,11 @@ QueryChat <- R6::R6Class( #' `$sidebar()` instead, which wraps this in a sidebar layout. #' #' @param ... Additional arguments passed to [shinychat::chat_ui()]. - #' @param ns A Shiny namespacing (i.e., [shiny::NS()]) function. - #' Only needed when calling this method within a module UI function. + #' @param id Optional ID for the QueryChat instance. If not provided, + #' will use the ID provided at initialization. This argument is included + #' for use within Shiny modules; in which case you'll need to provide + #' `id = ns("your_id")` where `ns` is the namespacing function from + #' [shiny::NS()]. #' #' @return A UI component containing the chat interface. #' @@ -525,27 +528,16 @@ QueryChat <- R6::R6Class( #' qc$ui() #' ) #' } - ui = function(..., ns = NULL) { - check_function(ns, allow_null = TRUE) + ui = function(..., id = NULL) { + check_string(id, allow_null = TRUE, allow_empty = FALSE) # If called within another module, the UI id needs to be namespaced # by that "parent" module. If called in a module *server* context, we # can infer the namespace from the session, but if not, the user # will need to provide it. - # NOTE: this isn't a problem for Python since id namespacing is handled implicitly - # by UI functions like shinychat.chat_ui(). - id <- self$id - id <- if (is.null(ns)) namespaced_id(id) else ns(id) - - # Provide a helpful error if the user tries to set id directly - if ("id" %in% names(list2(...))) { - cli::cli_abort( - c( - "Not allowed to set {.arg id} to {.fn $ui()} (or {.fn $sidebar()}).", - "i" = "Use the {.arg ns} argument instead to namespace the UI id." - ) - ) - } + # NOTE: this isn't a problem for Python since id namespacing is handled + # implicitly by UI functions like shinychat.chat_ui(). + id <- id %||% namespaced_id(self$id) mod_ui(id, ...) }, @@ -563,6 +555,10 @@ QueryChat <- R6::R6Class( #' with Shiny bookmarks. This requires that the Shiny app has bookmarking #' enabled via `shiny::enableBookmarking()` or the `enableBookmarking` #' parameter of `shiny::shinyApp()`. + #' @param ... Ignored. + #' @param id Optional module ID for the QueryChat instance. If not provided, + #' will use the ID provided at initialization. When used in Shiny modules, + #' this `id` should match the `id` used in the corresponding UI function. #' @param session The Shiny session object. #' #' @return A list containing session-specific reactive values and the chat @@ -586,8 +582,13 @@ QueryChat <- R6::R6Class( #' } server = function( enable_bookmarking = FALSE, + ..., + id = NULL, session = shiny::getDefaultReactiveDomain() ) { + check_string(id, allow_null = TRUE, allow_empty = FALSE) + check_dots_empty() + if (is.null(session)) { cli::cli_abort( "{.fn $server} must be called within a Shiny server function" @@ -595,7 +596,7 @@ QueryChat <- R6::R6Class( } mod_server( - self$id, + id %||% self$id, data_source = private$.data_source, greeting = self$greeting, client = self$client, diff --git a/pkg-r/man/QueryChat.Rd b/pkg-r/man/QueryChat.Rd index 083e214f2..5420bc26a 100644 --- a/pkg-r/man/QueryChat.Rd +++ b/pkg-r/man/QueryChat.Rd @@ -537,7 +537,7 @@ Create the UI for the querychat chat interface. This method generates the chat UI component. Typically you'll use \verb{$sidebar()} instead, which wraps this in a sidebar layout. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{QueryChat$ui(..., ns = NULL)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{QueryChat$ui(..., id = NULL)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -545,8 +545,11 @@ This method generates the chat UI component. Typically you'll use \describe{ \item{\code{...}}{Additional arguments passed to \code{\link[shinychat:chat_ui]{shinychat::chat_ui()}}.} -\item{\code{ns}}{A Shiny namespacing (i.e., \code{\link[shiny:NS]{shiny::NS()}}) function. -Only needed when calling this method within a module UI function.} +\item{\code{id}}{Optional ID for the QueryChat instance. If not provided, +will use the ID provided at initialization. This argument is included +for use within Shiny modules; in which case you'll need to provide +\code{id = ns("your_id")} where \code{ns} is the namespacing function from +\code{\link[shiny:NS]{shiny::NS()}}.} } \if{html}{\out{}} } @@ -580,6 +583,8 @@ reactive values. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{QueryChat$server( enable_bookmarking = FALSE, + ..., + id = NULL, session = shiny::getDefaultReactiveDomain() )}\if{html}{\out{
}} } @@ -594,6 +599,12 @@ with Shiny bookmarks. This requires that the Shiny app has bookmarking enabled via \code{shiny::enableBookmarking()} or the \code{enableBookmarking} parameter of \code{shiny::shinyApp()}.} +\item{\code{...}}{Ignored.} + +\item{\code{id}}{Optional module ID for the QueryChat instance. If not provided, +will use the ID provided at initialization. When used in Shiny modules, +this \code{id} should match the \code{id} used in the corresponding UI function.} + \item{\code{session}}{The Shiny session object.} } \if{html}{\out{}} From 053786cb5f326cef10913942695b7f624c379075 Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Wed, 17 Dec 2025 15:41:38 -0500 Subject: [PATCH 2/2] chore: Also `$sidebar()` and update docstrings --- pkg-r/R/QueryChat.R | 21 ++++++++++++--------- pkg-r/man/QueryChat.Rd | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/pkg-r/R/QueryChat.R b/pkg-r/R/QueryChat.R index ba1218fd3..863e4bd1e 100644 --- a/pkg-r/R/QueryChat.R +++ b/pkg-r/R/QueryChat.R @@ -474,8 +474,10 @@ QueryChat <- R6::R6Class( #' @param width Width of the sidebar in pixels. Default is 400. #' @param height Height of the sidebar. Default is "100%". #' @param fillable Whether the sidebar should be fillable. Default is `TRUE`. - #' @param ns A Shiny namespacing (i.e., [shiny::NS()]) function. - #' Only needed when calling this method within a module UI function. + #' @param id Optional ID for the QueryChat instance. If not provided, + #' will use the ID provided at initialization. If using `$sidebar()` in + #' a Shiny module, you'll need to provide `id = ns("your_id")` where `ns` + #' is the namespacing function from [shiny::NS()]. #' #' @return A [bslib::sidebar()] UI component. #' @@ -493,7 +495,7 @@ QueryChat <- R6::R6Class( width = 400, height = "100%", fillable = TRUE, - ns = NULL + id = NULL ) { bslib::sidebar( width = width, @@ -501,7 +503,7 @@ QueryChat <- R6::R6Class( fillable = fillable, class = "querychat-sidebar", ..., - self$ui(ns = ns) + self$ui(id = id) ) }, @@ -513,10 +515,9 @@ QueryChat <- R6::R6Class( #' #' @param ... Additional arguments passed to [shinychat::chat_ui()]. #' @param id Optional ID for the QueryChat instance. If not provided, - #' will use the ID provided at initialization. This argument is included - #' for use within Shiny modules; in which case you'll need to provide - #' `id = ns("your_id")` where `ns` is the namespacing function from - #' [shiny::NS()]. + #' will use the ID provided at initialization. If using `$ui()` in a Shiny + #' module, you'll need to provide `id = ns("your_id")` where `ns` is the + #' namespacing function from [shiny::NS()]. #' #' @return A UI component containing the chat interface. #' @@ -558,7 +559,9 @@ QueryChat <- R6::R6Class( #' @param ... Ignored. #' @param id Optional module ID for the QueryChat instance. If not provided, #' will use the ID provided at initialization. When used in Shiny modules, - #' this `id` should match the `id` used in the corresponding UI function. + #' this `id` should match the `id` used in the corresponding UI function + #' (i.e., `qc$ui(id = ns("your_id"))` pairs with `qc$server(id = + #' "your_id")`). #' @param session The Shiny session object. #' #' @return A list containing session-specific reactive values and the chat diff --git a/pkg-r/man/QueryChat.Rd b/pkg-r/man/QueryChat.Rd index 5420bc26a..64f15b0ac 100644 --- a/pkg-r/man/QueryChat.Rd +++ b/pkg-r/man/QueryChat.Rd @@ -489,7 +489,7 @@ interface, suitable for use with \code{\link[bslib:page_sidebar]{bslib::page_sid width = 400, height = "100\%", fillable = TRUE, - ns = NULL + id = NULL )}\if{html}{\out{}} } @@ -504,8 +504,10 @@ interface, suitable for use with \code{\link[bslib:page_sidebar]{bslib::page_sid \item{\code{fillable}}{Whether the sidebar should be fillable. Default is \code{TRUE}.} -\item{\code{ns}}{A Shiny namespacing (i.e., \code{\link[shiny:NS]{shiny::NS()}}) function. -Only needed when calling this method within a module UI function.} +\item{\code{id}}{Optional ID for the QueryChat instance. If not provided, +will use the ID provided at initialization. If using \verb{$sidebar()} in +a Shiny module, you'll need to provide \code{id = ns("your_id")} where \code{ns} +is the namespacing function from \code{\link[shiny:NS]{shiny::NS()}}.} } \if{html}{\out{}} } @@ -546,10 +548,9 @@ This method generates the chat UI component. Typically you'll use \item{\code{...}}{Additional arguments passed to \code{\link[shinychat:chat_ui]{shinychat::chat_ui()}}.} \item{\code{id}}{Optional ID for the QueryChat instance. If not provided, -will use the ID provided at initialization. This argument is included -for use within Shiny modules; in which case you'll need to provide -\code{id = ns("your_id")} where \code{ns} is the namespacing function from -\code{\link[shiny:NS]{shiny::NS()}}.} +will use the ID provided at initialization. If using \verb{$ui()} in a Shiny +module, you'll need to provide \code{id = ns("your_id")} where \code{ns} is the +namespacing function from \code{\link[shiny:NS]{shiny::NS()}}.} } \if{html}{\out{}} } @@ -603,7 +604,8 @@ parameter of \code{shiny::shinyApp()}.} \item{\code{id}}{Optional module ID for the QueryChat instance. If not provided, will use the ID provided at initialization. When used in Shiny modules, -this \code{id} should match the \code{id} used in the corresponding UI function.} +this \code{id} should match the \code{id} used in the corresponding UI function +(i.e., \code{qc$ui(id = ns("your_id"))} pairs with \code{qc$server(id = "your_id")}).} \item{\code{session}}{The Shiny session object.} }