@@ -74,7 +74,7 @@ QueryChat <- R6::R6Class(
7474 public = list (
7575 # ' @field greeting The greeting message displayed to users.
7676 greeting = NULL ,
77- # ' @field id The module ID for namespacing .
77+ # ' @field id ID for the QueryChat instance .
7878 id = NULL ,
7979 # ' @field tools The allowed tools for the chat client.
8080 tools = c(" update" , " query" ),
@@ -470,10 +470,12 @@ QueryChat <- R6::R6Class(
470470 # ' This method generates a [bslib::sidebar()] component containing the chat
471471 # ' interface, suitable for use with [bslib::page_sidebar()] or similar layouts.
472472 # '
473+ # ' @param ... Additional arguments passed to [bslib::sidebar()].
473474 # ' @param width Width of the sidebar in pixels. Default is 400.
474475 # ' @param height Height of the sidebar. Default is "100%".
475476 # ' @param fillable Whether the sidebar should be fillable. Default is `TRUE`.
476- # ' @param ... Additional arguments passed to [bslib::sidebar()].
477+ # ' @param ns A Shiny namespacing (i.e., [shiny::NS()]) function.
478+ # ' Only needed when calling this method within a module UI function.
477479 # '
478480 # ' @return A [bslib::sidebar()] UI component.
479481 # '
@@ -486,14 +488,20 @@ QueryChat <- R6::R6Class(
486488 # ' # Main content here
487489 # ' )
488490 # ' }
489- sidebar = function (width = 400 , height = " 100%" , fillable = TRUE , ... ) {
491+ sidebar = function (
492+ ... ,
493+ width = 400 ,
494+ height = " 100%" ,
495+ fillable = TRUE ,
496+ ns = NULL
497+ ) {
490498 bslib :: sidebar(
491499 width = width ,
492500 height = height ,
493501 fillable = fillable ,
494502 class = " querychat-sidebar" ,
495503 ... ,
496- self $ ui()
504+ self $ ui(ns = ns )
497505 )
498506 },
499507
@@ -504,6 +512,8 @@ QueryChat <- R6::R6Class(
504512 # ' `$sidebar()` instead, which wraps this in a sidebar layout.
505513 # '
506514 # ' @param ... Additional arguments passed to [shinychat::chat_ui()].
515+ # ' @param ns A Shiny namespacing (i.e., [shiny::NS()]) function.
516+ # ' Only needed when calling this method within a module UI function.
507517 # '
508518 # ' @return A UI component containing the chat interface.
509519 # '
@@ -515,8 +525,29 @@ QueryChat <- R6::R6Class(
515525 # ' qc$ui()
516526 # ' )
517527 # ' }
518- ui = function (... ) {
519- mod_ui(self $ id , ... )
528+ ui = function (... , ns = NULL ) {
529+ check_function(ns , allow_null = TRUE )
530+
531+ # If called within another module, the UI id needs to be namespaced
532+ # by that "parent" module. If called in a module *server* context, we
533+ # can infer the namespace from the session, but if not, the user
534+ # will need to provide it.
535+ # NOTE: this isn't a problem for Python since id namespacing is handled implicitly
536+ # by UI functions like shinychat.chat_ui().
537+ id <- self $ id
538+ id <- if (is.null(ns )) namespaced_id(id ) else ns(id )
539+
540+ # Provide a helpful error if the user tries to set id directly
541+ if (" id" %in% names(list2(... ))) {
542+ cli :: cli_abort(
543+ c(
544+ " Not allowed to set {.arg id} to {.fn $ui()} (or {.fn $sidebar()})." ,
545+ " i" = " Use the {.arg ns} argument instead to namespace the UI id."
546+ )
547+ )
548+ }
549+
550+ mod_ui(id , ... )
520551 },
521552
522553 # ' @description
@@ -826,3 +857,12 @@ normalize_data_source <- function(data_source, table_name) {
826857 " {.arg data_source} must be a {.cls DataSource}, {.cls data.frame}, or {.cls DBIConnection}, not {.obj_type_friendly {data_source}}."
827858 )
828859}
860+
861+
862+ namespaced_id <- function (id , session = shiny :: getDefaultReactiveDomain()) {
863+ if (is.null(session )) {
864+ id
865+ } else {
866+ session $ ns(id )
867+ }
868+ }
0 commit comments