Skip to content

Commit

Permalink
add cancellable login
Browse files Browse the repository at this point in the history
  • Loading branch information
DivadNojnarg committed May 24, 2024
1 parent 4910ad0 commit 2e19f9c
Show file tree
Hide file tree
Showing 15 changed files with 137 additions and 57 deletions.
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
- `f7Shadow()`removed from Framework7. No replacement. Will be removed in a future release.
- `f7Swipeout`: deprecate `side` parameter and `...`. Now use either `left`/`right` or both.
- `f7AutoComplete`: `value` now defaults to `NULL` (instead of the first choice).
- `updateF7Login()`: `id` is deprecated.

## Minor change
- `f7Messages()`: the corresponding input is now a list of lists, each item being a single `f7Message()`. The previous setting was not optimal R,the JS binding was returning a array of objects, which can't be easily translated to R. We now return an object of objects which becomes a list of lists.
Expand Down Expand Up @@ -94,7 +95,8 @@ the new router layout. Items must be wrapped in a `shiny::tagList()`.
- `updateF7App` can now also handle changes in app theme (ios or md), dark mode, and color.
- `f7Fabs()` has a new argument `global` that can be used to make FABs persistent across different tabs in `f7TabLayout()`.
- `f7ExpandableCard()` has a new argument `buttonColor` that can be used to control the color of the close button.
- `f7Login()` has a new argument `module` that can, optionally, be set to `FALSE` for more flexibility. For example, this allows you to use `f7Login()` inside your own modules, or without the provided `f7LoginServer()` module.
- `f7Login()` has a new argument `cancellable` that can, optionally, show a cancel button to close the login window. `f7LoginServer()` also return the cancel state so it can be used to trigger actions on the server side, like changing tab.
- `updateF7Login()`: new `cancel` parameter to close the login window.
- Fix various issues in documentation.
- Include new vignettes.

Expand Down
59 changes: 46 additions & 13 deletions R/f7Login.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#' as the button is pressed, its value is incremented which may be used to call
#' \link{updateF7Login}. `input$user` and `input$password` contains values passed
#' by the user in these respective fields and can be forwarded to \link{updateF7Login}.
#' `input$cancel` is increment whenever the login is closed when cancellable. You can access
#' the value and trigger other actions on the server, as shown in \link{f7LoginServer}.
#'
#' @param ... Slot for inputs like password, text, ...
#' @param id Login unique id.
Expand All @@ -16,18 +18,30 @@
#' @param startOpen Whether to open the login page at start. Default to TRUE. There
#' are some cases where it is interesting to set up to FALSE, for instance when you want
#' to have authentication only in a specific tab of your app (See example 2).
#' @param cancellable Whether to show a cancel button to close the login modal. Default
#' to FALSE.
#'
#' @export
#' @rdname authentication
#' @importFrom jsonlite toJSON
#' @example inst/examples/login/app.R
f7Login <- function(..., id, title, label = "Sign In", footer = NULL, startOpen = TRUE) {
f7Login <- function(..., id, title, label = "Sign In", footer = NULL, startOpen = TRUE,
cancellable = FALSE) {

ns <- shiny::NS(id)

submitBttn <- f7Button(inputId = ns("submit"), label = label)
submitBttn[[2]]$attribs$class <- "item-link list-button f7-action-button"
submitBttn[[2]]$name <- "a"
submitBttn <- f7Button(inputId = ns("submit"), label = label, fill = FALSE)

btnUI <- submitBttn

if (cancellable) {
cancelButton <- f7Button(ns("cancel"), label = "Cancel", fill = FALSE)
btnUI <- f7Grid(
cols = 2,
cancelButton,
submitBttn
)
}

shiny::tags$div(
id = sprintf("%s-login", id),
Expand Down Expand Up @@ -56,9 +70,7 @@ f7Login <- function(..., id, title, label = "Sign In", footer = NULL, startOpen
),
...
),
f7List(
submitBttn
),
btnUI,
if (!is.null(footer)) {
shiny::tags$div(class = "block-footer", footer)
}
Expand Down Expand Up @@ -103,8 +115,7 @@ f7LoginServer <- function(id, ignoreInit = FALSE, trigger = NULL) {
},
{
if (!authenticated()) updateF7Login()
},
once = TRUE
}
)

# toggle the login only if not authenticated
Expand All @@ -116,18 +127,26 @@ f7LoginServer <- function(id, ignoreInit = FALSE, trigger = NULL) {
user = input$user,
password = input$password
)
shiny::req(nchar(input$user) > 0, nchar(input$password) > 0)
authenticated(TRUE)
}
},
ignoreInit = ignoreInit
)

# Close on cancel
shiny::observeEvent(input$cancel, {
updateF7Login(cancel = TRUE)
})

# useful to export the user name outside the module
return(
list(
status = shiny::reactive(input$login),
user = shiny::reactive(input$user),
password = shiny::reactive(input$password)
password = shiny::reactive(input$password),
authenticated = shiny::reactive(authenticated()),
cancelled = shiny::reactive(input$cancel)
)
)
}
Expand All @@ -137,17 +156,31 @@ f7LoginServer <- function(id, ignoreInit = FALSE, trigger = NULL) {
#' Activates Framework7 login.
#'
#' \code{updateF7Login} toggles a login page.
#'
#'
#' @param id `r lifecycle::badge("deprecated")`.
#' @param user Value of the user input.
#' @param password Value of the password input.
#' @param cancel Whether to close the login. Default to FALSE.
#' @param session Shiny session object.
#' @export
#' @rdname authentication
updateF7Login <- function(user = NULL, password = NULL, session = shiny::getDefaultReactiveDomain()) {
updateF7Login <- function(id = deprecated(), user = NULL, password = NULL, cancel = FALSE, session = shiny::getDefaultReactiveDomain()) {

if (lifecycle::is_present(id)) {
lifecycle::deprecate_warn(
when = "2.0.0",
what = "updateF7Login(id)",
details = "id has been
deprecated will be removed from shinyMobile
in the next release."
)
}

message <- dropNulls(
list(
user = user,
password = password
password = password,
cancel = cancel
)
)
session$sendInputMessage("login", message)
Expand Down
6 changes: 4 additions & 2 deletions inst/examples/login/app.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ app <- shinyApp(
f7Link(label = "Link 1", href = "https://www.google.com"),
f7Link(label = "Link 2", href = "https://www.google.com")
),
f7Login(id = "login", title = "Welcome"),
f7Login(id = "login", title = "Welcome", cancellable = TRUE),
# main content
f7BlockTitle(
title = HTML(paste("Welcome", textOutput("user"))),
Expand All @@ -27,7 +27,9 @@ app <- shinyApp(
exportTestValues(
status = loginData$status(),
user = loginData$user(),
password = loginData$password()
password = loginData$password(),
authenticated = loginData$authenticated(),
cancelled = loginData$cancelled()
)

output$user <- renderText({
Expand Down
4 changes: 2 additions & 2 deletions inst/shinyMobile-2.0.0/dist/shinyMobile.min.css.map

Large diffs are not rendered by default.

56 changes: 28 additions & 28 deletions inst/shinyMobile-2.0.0/dist/shinyMobile.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions inst/shinyMobile-2.0.0/dist/shinyMobile.min.js.map

Large diffs are not rendered by default.

31 changes: 27 additions & 4 deletions man/authentication.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions srcjs/bindings/loginInputBinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@ $.extend(f7LoginBinding, {
// see updateF7Login
receiveMessage: function(el, data) {
if (this.instances[el.id].opened) {
// only close if valid password and user
if (data.user.length > 0 && data.password.length > 0) {
if (data.cancel) {
this.instances[el.id].close();
} else {
this.app.dialog.alert('Please enter a valid password and user.');
// only close if valid password and user
if (data.user.length > 0 && data.password.length > 0) {
this.instances[el.id].close();
} else {
this.app.dialog.alert('Please enter a valid password and user.');
}
}
} else {
this.instances[el.id].open();
Expand Down
2 changes: 2 additions & 0 deletions tests/testthat/_snaps/f7Login/login-app-001.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"export": {
"authenticated": false,
"cancelled": 0,
"password": "",
"status": true,
"user": ""
Expand Down
Binary file modified tests/testthat/_snaps/f7Login/login-app-001_.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions tests/testthat/_snaps/f7Login/login-app-002.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"export": {
"password": "pwd",
"authenticated": false,
"cancelled": 1,
"password": "",
"status": false,
"user": "usr"
"user": ""
}
}
Binary file modified tests/testthat/_snaps/f7Login/login-app-002_.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions tests/testthat/_snaps/f7Login/login-app-003.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"export": {
"authenticated": true,
"cancelled": 1,
"password": "pwd",
"status": true,
"user": "usr"
}
}
Binary file added tests/testthat/_snaps/f7Login/login-app-003_.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions tests/testthat/test-f7Login.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ test_that("login works", {
name = "login-app"
)

app$expect_values(export = TRUE)
app$click(selector = "#login-cancel")
app$wait_for_idle(2000)
app$expect_values(export = TRUE)

app$set_inputs("login-user" = "usr", "login-password" = "pwd")
Expand Down

0 comments on commit 2e19f9c

Please sign in to comment.