Limiting the number of users in a locally hosted R shiny app - r

I'd like to limit the number of users of my locally hosted r shiny app to one user at any one time.
So ideally when a second user attempted to run the app at the same time (users access the app by typing the local IP into the address field) the app would display a default message and stop any further progress. Nullifying any other user commands may not matter if the only thing shown upon entry is this denial message.
The content of the app doesn't matter so we can use this app as an example: http://shiny.rstudio.com/gallery/tabsets.html
Thanks for any help or info you can give.

I wouldn't recommend doing this, I think it's very dangerous, but there are ways you could hack this together. Here's one solution (as I said, it's hacky and I wouldn't do it myself). The basic idea is to have a global variable that keeps track of whether or not someone is using the app. If nobody is using the app, show the app and turn on the flag and make sure to turn off the flag when the user exits.
shinyBusy <- FALSE
runApp(shinyApp(
ui = fluidPage(
shinyjs::useShinyjs(),
shinyjs::hidden(
h1(id = "busyMsg", "App is busy")
),
shinyjs::hidden(
div(
id = "app",
p("Hello!")
)
)
),
server = function(input, output, session) {
if (shinyBusy) {
shinyjs::show("busyMsg")
} else {
shinyBusy <<- TRUE
session$onSessionEnded(function() shinyBusy <<- FALSE)
shinyjs::show("app")
}
}
),
launch.browser = TRUE)
Note: in order to show/hide app elements, I'm using a package that I wrote shinyjs

Related

Stop R Shiny from restoring selected inputs on page refresh

Whenever a user refreshes a page, any UI element that has been interacted with retains its new value instead of reverting to its default.
E.g. if I run the app below, change any of the inputs, then refresh the page, the new values are kept rather than the widgets being restored to 'A'.
I can appreciate this is useful in many situations, but is there a way to stop it from within Shiny, or is it controlled by the browser's cache? A hard refresh (ctrl F5) does indeed reset them back to 'A'.
library(shiny)
ui <- fluidPage(
selectInput("select", "Values", LETTERS[1:5], selected='A'),
radioButtons("radio", "Radio", LETTERS[1:5], selected='A'),
checkboxGroupInput("check", "Checkbox", LETTERS[1:5], selected='A')
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
I cannot really reproduce the problem, here's a GIF of what happens on my system when I refresh the browser (Chrome Version 94.0.4606.71):

Shiny: conditionally build UI

I'm building a Shiny dashboard to show a large amount of data. People access the dashboard through a separate login page (non-Shiny) that sits in front, at which point a JWT is generated and put in a cookie. I've managed to read in the cookie in Shiny and parse the data, saving the token in a variable called userPermissions. Now, however, I'd like to show/hide tabs in the dashboard depending on the user permissions.
For example: I have data on both managers and assistants. I want to show the manager data to any user with userPermissions == 'manager', and the assistant data to anyone with userPermissions == assistant.
I thought the best way would be to use conditionalPanel() – here's a (simplified) reproducible example:
library(shiny)
# UI file
ui <- fluidPage(
# JS to read cookie -- simplified to just return value!
tags$head(tags$script(
HTML('
Shiny.addCustomMessageHandler("goReadTheCookie", function (message) {
Shiny.onInputChange("cookie", "manager");
})
')
)
# Title
,titlePanel('Test')
# Navbar
,navbarPage(
id="navbar"
,conditionalPanel(condition = "userPermissions() == 'manager'",
mainPanel(textOutput('Manager data')))
,conditionalPanel(condition = "userPermissions() == 'assistant'",
mainPanel(textOutput('Assistant data')))
)
))
# Server file
server <- shinyServer(function(input, output,session){
## Grab permissions from Cookie
# Prepare output
userPermissions <- reactiveVal("")
# Tell JS to return cookie
session$sendCustomMessage(type="goReadTheCookie", message=list(name="cookie_name"))
# Listen for cookie
observeEvent(input$cookie,{
## -- Bunch of code omitted for sake of brevity -- ##
userPermissions("manager")
})
})
# Run app
shinyApp(ui=ui, server=server)
The problem with this code is that, in a browser console, I get the error Can't find variable: userPermissions.
I guess what's going on here is that the entire ui is executed, before JS can grab and return the cookie. What would be the best way to solve this?
Or, maybe I'm going about this the wrong way. I obviously need to verify the cookie server-side (i.e., in R) not to divulge the secret; and preferably this check, and the hiding/showing is completed at the very start of the Shiny application (userPermissions won't change during the session). Maybe there's a different (& better) solution to get to that point?
Any help would be very much appreciated!
In the end I found that the function appendTab does exactly what I was looking for. This needs to be run in server.R though, within the function to look for the cookie (otherwise userPermissions indeed doesn't exist). I could then do:
appendTab("navbar" # the id of the navigation bar created in ui.R
,tabPanel("tab name"
,mainPanel(...))
)
where tabPanel(...) could be anything you'd normally put in ui.R.
The added benefit here is that hidden tabs are also not available in the HTML source, as they're never even passed from the server to the client!

Can we reset page or object in r shiny without reloading page

Problem1: I created a shiny application in which when user commit any record to database entire page gets reloaded which i don't want i just want to reset/refresh my object in R shiny without entire page reload.Is there any alternative to achieve the same?
Problem2:Also in my application i have one login page so i want when user enters their credentials it should store the credentials in that field so that when user again login to the same page it should not ask to enter credentials along with password not by using browser functionality to remember password.Also when they close the browser and again open new instance of browser it should ask for credentials.
Any help would be appreciated. :)
it is always good if you have any reproducible example for your problem statement.
For your problem 1 there is a package shinyjs. You can use it for reset your object. The sample code for problem 1:
library(shiny)
library(shinyjs)
shinyApp(
ui = fluidPage(
shinyjs::useShinyjs(),
h2("shinyjs demo"),
textInput("name", "Name", ""),
actionButton("submit", "Submit"),
actionButton("reset", "Reset form")
),
server = function(input, output) {
observeEvent(input$submit, {
shinyjs::alert( paste("Thank you!",input$name) )
})
observeEvent(input$reset, {
shinyjs::reset("name")
})
}
)
You can have the documentation here. https://github.com/daattali/shinyjs
For your problem 2 there are few relative things. It can handled by browser also.
You can use this documentation link https://gist.github.com/calligross/e779281b500eb93ee9e42e4d72448189

how should I access shiny user's session info?

I'm wondering if there's any way I can access user log for my Shiny App.
Currently, I use the code below to get who logged in and when did this person log off.
However, I'd prefer to know the time the user logged in so that I'm able to know how long does the user using the app.
session$onSessionEnded(function(){
UserInfo <- data.frame(
LoginName = session$user,
Time = as.character(Sys.time())
)
Plus, I understand that Google Analytics can easily access this kind of info, but I do prefer a 'shiny' way to solve it.
I've also tried to use `session$clientData' as the document says it's used for "Getting Non-Input Data From the Client", but I don't know how could I get the login time.
Does anyone have any idea on how could I achieve this? Thanks in advance!
Per the shiny scoping rules, everything inside server <- function(input, output, session) is per-session.
server <- function(input, output, session) {
# everything in here is run once per-session, so it should run as soon as
# a user starts using the app
started <- Sys.time()
# ... reactives here ...
session$onSessionEnded(function() {
UserInfo <- data.frame(
LoginName = session$user,
Time = as.character(Sys.time())
)
# ... do something with UserInfo ...
})
In fact, the scoping rules suggest exactly this, but they named it startTime instead. (Hard things: cache invalidation and variable naming.)

Timing events when session ends

I am building a Shiny application, where I want to stop the (local) server when the client is closed. A simple way to achieve this is to include this in the shinyServer function:
session$onSessionEnded(function() {
stopApp()
})
A downside to this approach is if the user decides to hit refresh, then the app dies.
I have tried various workarounds, using e.g. reactiveTimer/invalidateLater to check for connections at certain intervals. However, these take a session reference (they are specific to the session), and so nothing will execute after onSessionEnded.
Is there a way to have a "global" server timer that executes regularly, and coould check for active connections? Or another way to achieve automatic application shut-down but which allows for a refresh of the page?
You could add an actionButton and some code on the server to stop the app when the button is clicked. For example:
runApp(list(
ui = bootstrapPage(
actionButton('close', "Close app")
),
server = function(input, output) {
observe({
if (input$close > 0) stopApp()
})
}
))
However, this won't automatically close the browser window (unless you're viewing with RStudio's built-in browser window). To do that, you need to add some Javascript to the actionButton.
runApp(list(
ui = bootstrapPage(
tags$button(
id = 'close',
type = "button",
class = "btn action-button",
onclick = "setTimeout(function(){window.close();},500);",
"Close window"
)
),
server = function(input, output) {
observe({
if (input$close > 0) stopApp()
})
}
))
Of course, this won't stop the app when the user closes the window some other way. I believe it's also possible to detect window close events in the browser, and then you may be able to set an input value (which goes to the server) at that time, but I don't know whether it'll get to the server before the window is closed and the Javascript stops running.

Resources