@@ -72,7 +72,7 @@ QueryChat <- R6::R6Class(
7272 public = list (
7373 # ' @field greeting The greeting message displayed to users.
7474 greeting = NULL ,
75- # ' @field id The module ID for namespacing .
75+ # ' @field id ID for the QueryChat instance .
7676 id = NULL ,
7777
7878 # ' @description
@@ -378,10 +378,12 @@ QueryChat <- R6::R6Class(
378378 # ' This method generates a [bslib::sidebar()] component containing the chat
379379 # ' interface, suitable for use with [bslib::page_sidebar()] or similar layouts.
380380 # '
381+ # ' @param ... Additional arguments passed to [bslib::sidebar()].
381382 # ' @param width Width of the sidebar in pixels. Default is 400.
382383 # ' @param height Height of the sidebar. Default is "100%".
383384 # ' @param fillable Whether the sidebar should be fillable. Default is `TRUE`.
384- # ' @param ... Additional arguments passed to [bslib::sidebar()].
385+ # ' @param ns A Shiny namespacing (i.e., [shiny::NS()]) function.
386+ # ' Only needed when calling this method within a module UI function.
385387 # '
386388 # ' @return A [bslib::sidebar()] UI component.
387389 # '
@@ -394,14 +396,20 @@ QueryChat <- R6::R6Class(
394396 # ' # Main content here
395397 # ' )
396398 # ' }
397- sidebar = function (width = 400 , height = " 100%" , fillable = TRUE , ... ) {
399+ sidebar = function (
400+ ... ,
401+ width = 400 ,
402+ height = " 100%" ,
403+ fillable = TRUE ,
404+ ns = NULL
405+ ) {
398406 bslib :: sidebar(
399407 width = width ,
400408 height = height ,
401409 fillable = fillable ,
402410 class = " querychat-sidebar" ,
403411 ... ,
404- self $ ui()
412+ self $ ui(ns = ns )
405413 )
406414 },
407415
@@ -412,6 +420,8 @@ QueryChat <- R6::R6Class(
412420 # ' `$sidebar()` instead, which wraps this in a sidebar layout.
413421 # '
414422 # ' @param ... Additional arguments passed to [shinychat::chat_ui()].
423+ # ' @param ns A Shiny namespacing (i.e., [shiny::NS()]) function.
424+ # ' Only needed when calling this method within a module UI function.
415425 # '
416426 # ' @return A UI component containing the chat interface.
417427 # '
@@ -423,8 +433,29 @@ QueryChat <- R6::R6Class(
423433 # ' qc$ui()
424434 # ' )
425435 # ' }
426- ui = function (... ) {
427- mod_ui(self $ id , ... )
436+ ui = function (... , ns = NULL ) {
437+ check_function(ns , allow_null = TRUE )
438+
439+ # If called within another module, the UI id needs to be namespaced
440+ # by that "parent" module. If called in a module *server* context, we
441+ # can infer the namespace from the session, but if not, the user
442+ # will need to provide it.
443+ # NOTE: this isn't a problem for Python since id namespacing is handled implicitly
444+ # by UI functions like shinychat.chat_ui().
445+ id <- self $ id
446+ id <- if (is.null(ns )) namespaced_id(id ) else ns(id )
447+
448+ # Provide a helpful error if the user tries to set id directly
449+ if (" id" %in% names(list2(... ))) {
450+ cli :: cli_abort(
451+ c(
452+ " Not allowed to set {.arg id} to {.fn $ui()} (or {.fn $sidebar()})." ,
453+ " i" = " Use the {.arg ns} argument instead to namespace the UI id."
454+ )
455+ )
456+ }
457+
458+ mod_ui(id , ... )
428459 },
429460
430461 # ' @description
@@ -724,3 +755,12 @@ normalize_data_source <- function(data_source, table_name) {
724755 " {.arg data_source} must be a {.cls DataSource}, {.cls data.frame}, or {.cls DBIConnection}, not {.obj_type_friendly {data_source}}."
725756 )
726757}
758+
759+
760+ namespaced_id <- function (id , session = shiny :: getDefaultReactiveDomain()) {
761+ if (is.null(session )) {
762+ id
763+ } else {
764+ session $ ns(id )
765+ }
766+ }
0 commit comments