MarkEdmondson1234 / googleAuthR

Google API Client Library for R. Easy authentication and help to build Google API R libraries with OAuth2. Shiny compatible.
https://code.markedmondson.me/googleAuthR
Other
175 stars 51 forks source link

rendering googleSignInUI through renderUI triggers a warning #152

Open romunov opened 5 years ago

romunov commented 5 years ago

What goes wrong

When rendering googleSignInUI through renderUI, a warning is issued. Blocker is disabled.

image

Steps to reproduce the problem

library(googleAuthR)

options(googleAuthR.webapp.client_id = "")

ui <- fluidPage(
  titlePanel("reproducible example"),
  sidebarLayout(
    sidebarPanel(
      uiOutput("signin")
      # googleSignInUI("google_signin")
    ),
    mainPanel()
  )
)

server <- function(input, output) {
  sign_ins <- shiny::callModule(module = googleSignIn,
                                id = "signin")
  output$signin <- renderUI({
    googleSignInUI("google_signin")
  })

}

shinyApp(ui, server)

Expected output

If you switch to "regular" rendering only in the UI part (commented), there is no warning. I believe the warning comes from signin-bottom.js. Unfortunately I'm not JS-savvy and I'm not sure how to catch this borderline case.

Actual output

(no output to consider)

Session Info

[1] googleAuthR_0.8.1.9000 gargle_0.3.0.9000      shiny_1.3.2 
MarkEdmondson1234 commented 5 years ago

The googleSingIn module loads the Google SignIn JavaScript on this line:

https://github.com/MarkEdmondson1234/googleAuthR/blob/473b93aeed05d79f9017ad7f350a8a2ab6989eb7/R/shiny-js-signin.R#L26

This needs to occur before any call to its JS library. The module shouldn't be wrapped in another renderUI, instead put the changes within the googleSignInUI function

romunov commented 5 years ago

If that's the case, I can't really bring data from server to UI to dynamically generate name on the button (e.g. "Logout (Roman)"). Or am I missing something?

MarkEdmondson1234 commented 5 years ago

You can pass in the argument to the UI module, so something like:

googleSignInUI <- function(id, logout_message = "Sign Out"){

  ns <- shiny::NS(id)

  if(getOption("googleAuthR.webapp.client_id") == ""){
    stop("You need to set options('googleAuthR.webapp.client_id' = 'your.client.id') - see website: https://code.markedmondson.me/googleAuthR/articles/google-authentication-types.html#googlesignin-module-example", call. = FALSE)
  }

  shiny::tagList(
    shiny::tags$head(
      shiny::tags$meta(name="google-signin-scope", content="profile email"),
      shiny::tags$meta(name="google-signin-client_id", content=getOption("googleAuthR.webapp.client_id")),
      shiny::HTML('<script src="https://apis.google.com/js/platform.js?onload=init"></script>')
    ),
    shiny::div(id=ns("signin"), class="g-signin2", "data-onsuccess"="onSignIn"),
    shiny::tags$button(id = ns("signout"),  logout_message, onclick="signOut();", class="btn-danger"),
    load_js_template("js/signin-top.js",
                     ns("signin"), ns("signout") ,ns("g_id"), ns("g_name"), ns("g_image"), ns("g_email")),
    load_js_template("js/signin-bottom.js",
                     ns("g_id"), ns("g_name"), ns("g_image"), ns("g_email"))
  )
}

And then in the ui.R it will be called via:

ui <- fluidPage(
  titlePanel("reproducible example"),
  sidebarLayout(
    sidebarPanel(
      googleSignInUI("google_signin", logout_message="My Sign Out")
    ),
    mainPanel()
  )
)
MarkEdmondson1234 commented 5 years ago

I'm not sure how server side variables can be passed into Shiny UI modules, would need to look that up.

romunov commented 5 years ago

So far the only way I've seen passing data from server side to UI was by rendering UI on the server side (e.g. here).