>.
596 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export(chat_server)
4 | export(chat_ui)
5 | export(updateChatTextInput)
6 | import(shiny)
7 | importFrom(DBI,dbExecute)
8 | importFrom(DBI,dbGetQuery)
9 | importFrom(R6,R6Class)
10 | importFrom(data.table,fread)
11 | importFrom(data.table,fwrite)
12 | importFrom(data.table,setnames)
13 | importFrom(purrr,map2)
14 |
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # shinyChatR 1.2.0
2 |
3 | * Added function updateChatTextInput to update the text input field
4 | * Added functionality that hitting enter automatically submits message
5 |
6 | # shinyChatR 1.1.0
7 |
8 | * Added option to use csv file to store messages
9 | * Use reactiveFileReader for csv files and rds files
10 | * Clean the input after sending
11 |
12 |
13 | # shinyChatR 1.0.0
14 |
15 | * First release on CRAN: Shiny module to add chat interface to shiny app
16 | * Added a `NEWS.md` file to track changes to the package.
17 |
--------------------------------------------------------------------------------
/R/CSVConnection.R:
--------------------------------------------------------------------------------
1 | #' CSVConnection R6 Class
2 | #'
3 | #' An R6 class representing a connection to a CSV file for the chat module.
4 | #'
5 | #'
6 | #' @field csv_path The path to the CSV file.
7 | #' @field nlast The number of messages to be read in and displayed.
8 | #'
9 | CSVConnection <- R6::R6Class("CSVConnection",
10 | public = list(
11 | csv_path = NULL,
12 | nlast = NULL,
13 | #' Initialize the R6 Object
14 | #'
15 | #' @param csv_path The path to the csv file.
16 | #' @param nlast The number of messages to be read-in.
17 | #' @importFrom data.table fwrite setnames fread
18 | initialize = function(csv_path, nlast=NULL) {
19 | self$csv_path <- csv_path
20 | self$nlast <- nlast
21 | if(!file.exists(csv_path)) {
22 | df <- data.frame(
23 | user = character(),
24 | text = character(),
25 | time = double()
26 | )
27 | data.table::fwrite(df, csv_path)
28 | }
29 | },
30 | #' @description Reads the full dataset
31 | #'
32 | #' @returns The full dataset
33 | #'
34 | get_data = function() {
35 | if(is.null(self$nlast)) {
36 | data.table::fread(self$csv_path)
37 | } else {
38 | data.table::setnames(
39 | data.table::fread(cmd = paste0("tail -",self$nlast,
40 | " '",self$csv_path,"'")),
41 | names(data.table::fread(self$csv_path,nrows = 0))
42 | )[]
43 | }
44 | },
45 | #' Save a message to data source
46 | #'
47 | #' @param message The message to be stores
48 | #' @param user The user who entered the message
49 | #' @param time The time when message was submitted
50 | #'
51 | insert_message = function(message, user, time) {
52 | chat_data <- data.frame(
53 | user = user,
54 | text = message,
55 | time = time)
56 | data.table::fwrite(chat_data, file=self$csv_path,
57 | quote=TRUE, append=TRUE)
58 | }
59 | )
60 | )
61 |
--------------------------------------------------------------------------------
/R/DBConnection.R:
--------------------------------------------------------------------------------
1 |
2 | #' DBConnection R6 Class
3 | #'
4 | #' An R6 class representing a connection to a database for the chat module.
5 | #'
6 | #' @field connection A database connection object, created using a package such as RSQLite.
7 | #' @field table The table that contains the chat information.
8 | #'
9 | #'
10 | DBConnection <- R6::R6Class("DBConnection",
11 | public = list(
12 | connection = NULL,
13 | table = NULL,
14 | #' Initialize the R6 Object
15 | #'
16 | #' @param connection DB connection
17 | #' @param table Table name
18 | #'
19 | #'
20 | initialize = function(connection, table="chat_data") {
21 | db.exists <- DBI::dbExistsTable(connection, table)
22 | if(!db.exists) {
23 | df <- data.frame(
24 | user = character(),
25 | text = character(),
26 | time = double())
27 | DBI::dbWriteTable(connection, table, df)
28 | }
29 | self$connection <- connection
30 | self$table <- table
31 | },
32 | #' @description Reads the full dataset
33 | #'
34 | #' @returns The full dataset
35 | #'
36 | get_data = function() {
37 | DBI::dbGetQuery(self$connection, paste('SELECT * FROM', self$table))
38 | },
39 | #' Save a message to data source
40 | #'
41 | #' @param message The message to be stores
42 | #' @param user The user who entered the message
43 | #' @param time The time when message was submitted
44 | #'
45 | insert_message = function(message, user, time) {
46 | DBI::dbExecute(self$connection, paste('INSERT INTO', self$table, '(user, text, time)
47 | VALUES (?, ?, ?);'),
48 | list(user, message, time))
49 | }
50 | )
51 | )
52 |
--------------------------------------------------------------------------------
/R/RDSConnection.R:
--------------------------------------------------------------------------------
1 | #' RDSConnection R6 Class
2 | #'
3 | #' An R6 class representing a connection to a rds file for the chat module.
4 | #'
5 | #' @field rds_path The path to the rds file.
6 | #'
7 | RDSConnection <- R6::R6Class("RDSConnection",
8 | public = list(
9 | rds_path = NULL,
10 | #' Initialize the R6 Object
11 | #'
12 | #' @param rds_path The path to the rds file.
13 | #'
14 | initialize = function(rds_path) {
15 | self$rds_path <- rds_path
16 | if(!file.exists(rds_path)) {
17 | df <- data.frame(
18 | ## rowid = numeric(),
19 | user = character(),
20 | text = character(),
21 | time = double())
22 | saveRDS(df, rds_path)
23 | }
24 | },
25 | #' @description Reads the full dataset
26 | #'
27 | #' @returns The full dataset
28 | #'
29 | get_data = function() {
30 | readRDS(file = self$rds_path)
31 | },
32 | #' Save a message to data source
33 | #'
34 | #' @param message The message to be stores
35 | #' @param user The user who entered the message
36 | #' @param time The time when message was submitted
37 | #'
38 | insert_message = function(message, user, time) {
39 | prev_chat_data <- readRDS(file = self$rds_path)
40 | chat_data <- rbind(
41 | prev_chat_data,
42 | data.frame(
43 | user = user,
44 | text = message,
45 | time = time
46 | ))
47 | saveRDS(chat_data, file = self$rds_path)
48 | }
49 | )
50 | )
51 |
--------------------------------------------------------------------------------
/R/chat.R:
--------------------------------------------------------------------------------
1 | #' @title A chat module for Shiny apps - UI
2 | #'
3 | #' @description Creates the user interface for the chat module, which includes a chat message display area, a text input field for entering new messages, and a send button.
4 | #'
5 | #' @param id The id of the module
6 | #' @param height The height of the chat display area. Default is 300px.
7 | #' @param width The width of the chat display area.
8 | #' @param ui_title The title of the chat area.
9 | #'
10 | #' @import shiny
11 | #'
12 | #' @export
13 | #'
14 | chat_ui <- function(id, ui_title='', height = "300px", width = "100%") {
15 |
16 | ns <- NS(id)
17 | js <- paste0('
18 | $(document).on("keyup", function(e) {
19 | if(e.keyCode == 13){
20 | document.getElementById("', ns("chatFromSend"), '").click();
21 | }
22 | });')
23 | div(width = width,
24 | includeCSS(system.file("assets/shinyChatR.css", package = "shinyChatR")),
25 | tags$script(HTML(
26 | js
27 | )),
28 | div(class = "chatContainer",
29 | div(class = "chatTitle", ui_title),
30 | div(class = "chatMessages",
31 | style = paste0("height:", height),
32 | # Display messages here
33 | uiOutput(ns("chatbox"))
34 | ),
35 | tags$form(class = "chatForm",
36 | tags$input(type = "text",
37 | id = ns("chatInput"),
38 | placeholder = "Enter message"),
39 | actionButton(inputId = ns("chatFromSend"),
40 | ## label = "Send",
41 | label = NULL,
42 | width = "70px",
43 | icon = icon("paper-plane"),
44 | style = "background-color: #007bc2;
45 | color: #fff; height:32px;padding:0px;")
46 | )
47 | )
48 | )
49 | }
50 |
51 | #' @title A chat module for Shiny apps - server
52 | #'
53 | #' @description Creates the server logic for the chat module, which handles adding new messages to the database or RDS file, and retrieving messages to display
54 | #'
55 | #' @param id The id of the module.
56 | #' @param chat_user The user name that should be displayed next to the message.
57 | #' @param db_connection A database connection object, created using the \code{DBI} package. If provided, the chat messages will be stored in a database table.
58 | #' @param db_table_name he name of the database table to use for storing the chat messages. If \code{db_connection} is provided, this parameter is required.
59 | #' @param rds_path The path to an RDS file to use for storing the chat messages. If provided, the chat messages will be stored in an RDS file.
60 | #' @param csv_path The path to an csv file to use for storing the chat messages. If provided, the chat messages will be stored in an csv file.
61 | #' @param invalidateDSMillis The milliseconds to wait before the data source is read again. The default is 1 second.
62 | #' @param nlast The number of last messages to be read in and displayed
63 | #' @param pretty Logical that determines if the date should be displayed in a pretty format
64 | #'
65 | #' @return the reactive values \code{chat_rv} with all the chat information
66 | #'
67 | #' @import shiny
68 | #' @importFrom R6 R6Class
69 | #' @importFrom DBI dbGetQuery dbExecute
70 | #'
71 | #' @export
72 | #'
73 | chat_server <- function(id,
74 | chat_user,
75 | db_connection = NULL,
76 | db_table_name = "chat_data",
77 | rds_path = NULL,
78 | csv_path = NULL,
79 | invalidateDSMillis = 1000,
80 | pretty = TRUE,
81 | nlast = 100
82 | ) {
83 |
84 | moduleServer(
85 | id,
86 | function(input, output, session) {
87 |
88 | ns <- session$ns
89 |
90 | # data source can only be a db or rds file
91 | if (sum(!is.null(c(db_connection,rds_path,csv_path)))>1){
92 | stop("Either specify only one DB connection, DB file, RDS or CSV path")
93 | }
94 |
95 | # initiate data source R6
96 | if (!is.null(db_connection)){
97 | ChatData <- DBConnection$new(db_connection, db_table_name)
98 | # check if it contains the necessary variables
99 | if (!all(c("text", "user", "time") %in% names(ChatData$get_data()))){
100 | stop("The dataframe does not have the necessary columns text, user and time")
101 | }
102 | } else if (!is.null(rds_path)){
103 | ChatData <- RDSConnection$new(rds_path)
104 | if (!all(c("text", "user", "time") %in% names(ChatData$get_data()))){
105 | stop("The dataframe does not have the necessary columns text, user and time")
106 | }
107 | } else if (!is.null(csv_path)){
108 | ChatData <- CSVConnection$new(csv_path, n=nlast)
109 | if (!all(c("text", "user", "time") %in% names(ChatData$get_data()))){
110 | stop("The dataframe does not have the necessary columns text, user and time")
111 | }
112 | } else {
113 | stop("Either 'db_connection', 'rds_path' or 'csv_path' must be specified.")
114 | }
115 |
116 | if(is.null(db_connection)){
117 | ## get non-NULL file
118 | data_file <- c(rds_path,csv_path)[1]
119 | reactive_chatData <- shiny::reactiveFileReader(
120 | invalidateDSMillis, session, data_file, function(f) ChatData$get_data()
121 | )
122 | }
123 |
124 | # Add code for sending and receiving messages here
125 | chat_rv <- reactiveValues(chat = ChatData$get_data())
126 |
127 | output$chatbox <- renderUI({
128 | if (nrow(chat_rv$chat)>0) {
129 | # prepare the message elements
130 | render_msg_divs2(
131 | chat_rv$chat$text,
132 | chat_rv$chat$user,
133 | # check if it is a reactive element or not
134 | ifelse(is.reactive(chat_user), chat_user(), chat_user),
135 | strftime(chat_rv$chat$time),
136 | pretty = pretty
137 | )
138 | } else {
139 | tags$span(" ")
140 | }
141 | })
142 |
143 |
144 | # for connection regularly check for updates
145 | if(!is.null(db_connection)){
146 | observe({
147 | # reload chat data
148 | invalidateLater(invalidateDSMillis)
149 | chat_rv$chat <- ChatData$get_data()
150 | })
151 | } else { # for csv and rds use reactiveFileReader
152 | observe({
153 | # reload chat data
154 | chat_rv$chat <- reactive_chatData()
155 | })
156 | }
157 |
158 | observeEvent( input$chatFromSend, {
159 | if(input$chatInput=="") return()
160 | ChatData$insert_message(
161 | user = ifelse(is.reactive(chat_user), chat_user(), chat_user),
162 | message = input$chatInput,
163 | time = strftime(Sys.time())
164 | )
165 | ## chat_rv$chat <- ChatData$get_data() ## not needed??
166 | updateTextInput(session, "chatInput", value='')
167 | })
168 |
169 | return(chat_rv)
170 | })
171 | }
172 |
173 | #' @title A function to update the chat textInput
174 | #'
175 | #' @description Updates the value of the chat textInput
176 | #'
177 | #' @param session The shiny session.
178 | #' @param id The id of the module.
179 | #' @param value The new value that should be shown in the chat textInput.
180 | #'
181 | #'
182 | #' @import shiny
183 | #'
184 | #' @export
185 | #'
186 | updateChatTextInput <- function(session = getDefaultReactiveDomain(),
187 | id,
188 | value
189 | ) {
190 | ns <- NS(id)
191 |
192 | updateTextInput(session = session, inputId = ns("chatInput"), value = value)
193 | invisible(ns("chatInput"))
194 | }
195 |
196 |
--------------------------------------------------------------------------------
/R/utils.R:
--------------------------------------------------------------------------------
1 | #' Render the messages for the chat
2 | #'
3 | #' @param texts a character vector with the texts
4 | #' @param users a character vector with the users
5 | #' @param act_user a character with the current user (that is using the app)
6 | #'
7 | #' @return The HTML code containing the chat messages
8 | #'
9 | #' @importFrom purrr map2
10 | #'
11 | render_msg_divs <- function(texts, users, act_user) {
12 | purrr::map2(texts, users,
13 | ~ div(class=paste0("chatMessage", ifelse(.y == act_user, " me", "")),
14 | p(tags$strong(.y), .x))
15 | )
16 | }
17 |
18 | #' Render the messages for the chat
19 | #'
20 | #' @param texts a character vector with the texts
21 | #' @param users a character vector with the users
22 | #' @param act_user a character with the current user (that is using the app)
23 | #' @param time a datetime object
24 | #' @param pretty a logical that indicates if it should simplify the date
25 | #'
26 | #' @return The HTML code containing the chat messages
27 | #'
28 | #' @importFrom purrr map2
29 | #'
30 | render_msg_divs2 <- function(texts, users, act_user, time, pretty=TRUE) {
31 |
32 | ## detect change of day
33 | xtime <- as.POSIXct(time, origin="1970-01-01")
34 | dx <- diff(as.integer(factor(weekdays(xtime))))
35 | first_otd <- c(TRUE,dx!=0) ## first of the day message
36 | dd <- as.integer(format(xtime, format="%d"))
37 | if(pretty) {
38 | date <- paste(weekdays(xtime), dd, months(xtime))
39 | } else {
40 | date <- strftime(time)
41 | }
42 | now <- strftime(Sys.time())
43 | today <- substring(now, 1,10)
44 | is.today <- (substring(xtime,1,10) == today)
45 | if(any(is.today)) date[which(is.today)] <- "Today"
46 | dt <- data.frame(user=users, text=texts, date=date, first=first_otd)
47 |
48 | formatChat <- function(a) {
49 | div(
50 | class="row",
51 | div(
52 | class = paste(
53 | 'col-12 chatTime',
54 | ifelse( a['first'], 'first','not-first')
55 | ),
56 | a['date']
57 | ),
58 | div(
59 | class = paste(
60 | "col-12 chatMessage",
61 | ifelse(a['user'] == act_user,"me", "")
62 | ),
63 | span(a['user'], class='chatUser'),
64 | span(a['text'], class='chatText')
65 | )
66 | )
67 | }
68 |
69 | chats <- apply(dt, 1, c, simplify=FALSE)
70 | tags <- lapply(chats, function(a) formatChat(a))
71 | div( class="container chatInnerContainer", tags)
72 | }
73 |
--------------------------------------------------------------------------------
/README.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | output: github_document
3 | ---
4 |
5 |
6 |
7 | ```{r, include = FALSE}
8 | knitr::opts_chunk$set(
9 | collapse = TRUE,
10 | comment = "#>",
11 | fig.path = "man/figures/README-",
12 | out.width = "100%"
13 | )
14 | ```
15 |
16 | # shinyChatR
17 |
18 |
19 | [](https://github.com/julianschmocker/shinyChatR/actions/workflows/test-coverage.yaml)
20 |
21 |
22 | This package provides a reusable chat module for R Shiny apps. The module allows multiple users to connect to a common chat and send messages to each other in real-time.
23 |
24 | The messages can either be stored in a database or a rds data. Here is an example of the UI:
25 |
26 | {width=460}
27 |
28 |
29 | ## Features
30 |
31 | * Real-time chat: messages are sent and received in real-time, without the need to refresh the page. It is possible to specify how often the data source should be read.
32 | * Multiple users: multiple users can connect to the chat room and send messages to each other.
33 | * Persistent messages: chat messages are stored in a database or rds file, allowing them to be retrieved and viewed even after a user logs out or the app is closed.
34 |
35 | ## General Usage
36 |
37 | To use the chat module in your own Shiny app, follow these steps:
38 |
39 | 1. Install the package
40 | 2. Load the package `library("shinyChatR")`
41 | 3. Initialize the database table or rds file
42 | 4. Add chat module to the app
43 |
44 | The details of the different steps can be found below:
45 |
46 | ## Database connection for storing chat data
47 |
48 | If you are using a database connection to store the chat messages, you will need to initialize the database table before using the chat module. The following example shows an example how to do this using the `DBI` and `RSQLite` packages. Replace `db_file` with the path to your database file. The data will be saved in the table `chat_data`.
49 |
50 | ```{r, eval = FALSE}
51 | library(DBI)
52 | library(RSQLite)
53 |
54 | db_file <- "path_to_your_database_file"
55 | conn <- dbConnect(RSQLite::SQLite(), db_file)
56 |
57 | ```
58 |
59 | If the table does not yet exist, it will be created in the specified connection. Now you can add the chat module to your app:
60 |
61 | ```{r, eval = FALSE}
62 | library(shinyChatR)
63 | ui <- fluidPage(
64 | chat_ui("test")
65 | )
66 |
67 | server <- function(input, output, server) {
68 | chat_server("test", db_connection = conn,
69 | db_table_name = "chat_data",
70 | chat_user = "user1")
71 | }
72 |
73 | # Run the application
74 | shinyApp(ui = ui, server = server)
75 | ```
76 |
77 | ## RDS file for storing chat data
78 |
79 | A similar approach is required for rds data.
80 |
81 | ```{r, eval = FALSE}
82 | df <- data.frame(rowid = numeric(),
83 | user = character(),
84 | text = character(),
85 | time = double())
86 |
87 | #
88 | test_rds <- "path_to_rds_file.rds"
89 | saveRDS(df, test_rds)
90 | ```
91 |
92 | It is not necessary to initiate the rds file. It will be created if it does not exist.
93 | Now you can add the chat module to your app:
94 |
95 | ```{r, eval = FALSE}
96 | library(shinyChatR)
97 | test_rds <- "path_to_rds_file.rds"
98 |
99 | ui <- fluidPage(
100 | chat_ui("test2")
101 | )
102 |
103 | server <- function(input, output, server) {
104 | chat_server("test2",
105 | rds_path = test_rds,
106 | chat_user = "user2")
107 | }
108 |
109 | # Run the application
110 | shinyApp(ui = ui, server = server)
111 | ```
112 |
113 | ## Installation
114 |
115 | Install from CRAN with
116 |
117 | ```{r, eval = FALSE}
118 | install.packages("shinyChatR")
119 | ```
120 |
121 | You can install the development version of shinyChatR from
122 | [GitHub](https://github.com/julianschmocker/shinyChatR) with:
123 |
124 | ```{r, eval = FALSE}
125 | remotes::install_github("julianschmocker/shinyChatR")
126 | ```
127 |
128 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # shinyChatR
5 |
6 |
7 |
8 | [](https://github.com/julianschmocker/shinyChatR/actions/workflows/test-coverage.yaml)
10 |
11 |
12 | This package provides a reusable chat module for R Shiny apps. The
13 | module allows multiple users to connect to a common chat and send
14 | messages to each other in real-time.
15 |
16 | The messages can either be stored in a database or a rds data. Here is
17 | an example of the UI:
18 |
19 |
22 |
23 |
24 | ## Features
25 |
26 | - Real-time chat: messages are sent and received in real-time, without
27 | the need to refresh the page. It is possible to specify how often the
28 | data source should be read.
29 | - Multiple users: multiple users can connect to the chat room and send
30 | messages to each other.
31 | - Persistent messages: chat messages are stored in a database or rds
32 | file, allowing them to be retrieved and viewed even after a user logs
33 | out or the app is closed.
34 |
35 | ## General Usage
36 |
37 | To use the chat module in your own Shiny app, follow these steps:
38 |
39 | 1. Install the package
40 | 2. Load the package `library("shinyChatR")`
41 | 3. Initialize the database table or rds file
42 | 4. Add chat module to the app
43 |
44 | The details of the different steps can be found below:
45 |
46 | ## Database connection for storing chat data
47 |
48 | If you are using a database connection to store the chat messages, you
49 | will need to initialize the database table before using the chat module.
50 | The following example shows an example how to do this using the `DBI`
51 | and `RSQLite` packages. Replace `db_file` with the path to your database
52 | file. The data will be saved in the table `chat_data`.
53 |
54 | ``` r
55 | library(DBI)
56 | library(RSQLite)
57 |
58 | db_file <- "path_to_your_database_file"
59 | conn <- dbConnect(RSQLite::SQLite(), db_file)
60 | ```
61 |
62 | If the table does not yet exist, it will be created in the specified
63 | connection. Now you can add the chat module to your app:
64 |
65 | ``` r
66 | library(shinyChatR)
67 | ui <- fluidPage(
68 | chat_ui("test")
69 | )
70 |
71 | server <- function(input, output, server) {
72 | chat_server("test", db_connection = conn,
73 | db_table_name = "chat_data",
74 | chat_user = "user1")
75 | }
76 |
77 | # Run the application
78 | shinyApp(ui = ui, server = server)
79 | ```
80 |
81 | ## RDS file for storing chat data
82 |
83 | A similar approach is required for rds data.
84 |
85 | ``` r
86 | df <- data.frame(rowid = numeric(),
87 | user = character(),
88 | text = character(),
89 | time = double())
90 |
91 | #
92 | test_rds <- "path_to_rds_file.rds"
93 | saveRDS(df, test_rds)
94 | ```
95 |
96 | It is not necessary to initiate the rds file. It will be created if it
97 | does not exist. Now you can add the chat module to your app:
98 |
99 | ``` r
100 | library(shinyChatR)
101 | test_rds <- "path_to_rds_file.rds"
102 |
103 | ui <- fluidPage(
104 | chat_ui("test2")
105 | )
106 |
107 | server <- function(input, output, server) {
108 | chat_server("test2",
109 | rds_path = test_rds,
110 | chat_user = "user2")
111 | }
112 |
113 | # Run the application
114 | shinyApp(ui = ui, server = server)
115 | ```
116 |
117 | ## Installation
118 |
119 | Install from CRAN with
120 |
121 | ``` r
122 | install.packages("shinyChatR")
123 | ```
124 |
125 | You can install the development version of shinyChatR from
126 | [GitHub](https://github.com/julianschmocker/shinyChatR) with:
127 |
128 | ``` r
129 | remotes::install_github("julianschmocker/shinyChatR")
130 | ```
131 |
--------------------------------------------------------------------------------
/_pkgdown.yml:
--------------------------------------------------------------------------------
1 | url: https://julianschmocker.github.io/shinyChatR/
2 | template:
3 | bootstrap: 5
4 |
5 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | comment: false
2 |
3 | coverage:
4 | status:
5 | project:
6 | default:
7 | target: auto
8 | threshold: 1%
9 | informational: true
10 | patch:
11 | default:
12 | target: auto
13 | threshold: 1%
14 | informational: true
15 |
--------------------------------------------------------------------------------
/cran-comments.md:
--------------------------------------------------------------------------------
1 | ## R CMD check results
2 |
3 | 0 errors | 0 warnings | 0 notes
4 |
5 | ## Downstream dependencies
6 | There are no downstream dependencies
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/inst/assets/shinyChatR.css:
--------------------------------------------------------------------------------
1 | /* Chat Container */
2 | .chatContainer {
3 | margin: 0 auto;
4 | padding: 10px;
5 | border: 1px solid #ccc;
6 | border-radius: 5px;
7 | box-shadow: 2px 2px 10px #ccc;
8 | }
9 |
10 | .chatInnerContainer {
11 | width: 100%;
12 | margin: auto;
13 | padding: 0px 15px 0 10px;
14 | }
15 |
16 | /* Chat Messages */
17 | .chatMessages {
18 | flex-grow: 1;
19 | overflow-y: auto;
20 | display: flex;
21 | flex-direction: column-reverse;
22 | padding: 5px 5px;
23 | border-radius: 5px;
24 | margin-bottom: 5px;
25 | }
26 |
27 |
28 | /* Chat Message */
29 | .chatMessage {
30 | float: left;
31 | width: auto;
32 | margin-bottom: 5px;
33 | padding: 2px 10px 2px 5px;
34 | border-radius: 5px;
35 | background-color: #eee;
36 | clear: both;
37 | box-shadow: 1px 1px 5px #ccc;
38 | }
39 |
40 | .chatMessage.me {
41 | float: right;
42 | margin-left: auto;
43 | background-color: #2196f3;
44 | color: #fff;
45 | }
46 |
47 | /* Chat Form */
48 | .chatForm {
49 | display: flex;
50 | margin-top: 10px;
51 | }
52 |
53 | /* Chat Input */
54 | .chatForm input {
55 | flex-grow: 1;
56 | padding: 5px;
57 | border-radius: 5px;
58 | border: 1px solid #ccc;
59 | margin-right: 5px;
60 | }
61 |
62 | /* Chat Button */
63 | .chatForm button {
64 | background-color: #007bff;
65 | padding: 10px 10px;
66 | border-radius: 5px;
67 | border: none;
68 | cursor: pointer;
69 | }
70 |
71 | .chatUser {
72 | font-weight: 600;
73 | padding: 0 8px 0 5px;
74 | }
75 |
76 | .chatUser {
77 | font-weight: 600;
78 | padding: 0 8px 0 5px;
79 | }
80 |
81 | .chatTime.first {
82 | text-align: center;
83 | background-color: aliceblue;
84 | margin: 20px 0px;
85 | padding: 4px;
86 | }
87 |
88 | .chatTime.not-first {
89 | display: none;
90 | }
91 |
--------------------------------------------------------------------------------
/inst/examples/example_csv.R:
--------------------------------------------------------------------------------
1 |
2 | library(shinyChatR)
3 |
4 | # temp csv
5 | test_csv <- file.path(tempdir(), "test.csv")
6 |
7 |
8 | ui <- fluidPage(
9 |
10 | fluidRow(
11 | column(width = 6,
12 | # add chat ui elements
13 | chat_ui("test4"),
14 | )
15 | )
16 | )
17 |
18 |
19 | server <- function(input, output, server) {
20 |
21 | # corresponding server part for id test1
22 | chat_server("test4", csv_path = test_csv,
23 | chat_user = "user1"
24 | )
25 | }
26 |
27 |
28 | # Run the application
29 | shinyApp(ui = ui, server = server)
30 |
--------------------------------------------------------------------------------
/inst/examples/example_db.R:
--------------------------------------------------------------------------------
1 |
2 | library(shinyChatR)
3 |
4 | # store db as tempfile. Select different path to store db locally
5 | tempdb <- file.path(tempdir(), "db")
6 |
7 | con <- dbConnect(RSQLite::SQLite(), tempdb)
8 |
9 |
10 | ui <- fluidPage(
11 |
12 | fluidRow(
13 | column(width = 6,
14 | # add chat ui elements
15 | chat_ui("test1"),
16 | )
17 | )
18 | )
19 |
20 |
21 | server <- function(input, output, server) {
22 |
23 | # corresponding server part for id test1
24 | chat_server("test1", db_connection = con,
25 | db_table_name = "chat_data",
26 | chat_user = "user1"
27 | )
28 | }
29 |
30 |
31 | # Run the application
32 | shinyApp(ui = ui, server = server)
33 |
--------------------------------------------------------------------------------
/inst/examples/example_db_reactive_user.R:
--------------------------------------------------------------------------------
1 |
2 | library(shinyChatR)
3 | library(shiny)
4 | library(DBI)
5 | library(R6)
6 |
7 | # store db as tempfile. Select different path to store db locally
8 | tempdb <- file.path(tempdir(), "db")
9 |
10 | con <- dbConnect(RSQLite::SQLite(), tempdb)
11 |
12 | # initiate chat table
13 | df <- data.frame(rowid = numeric(),
14 | user = character(),
15 | text = character(),
16 | time = double())
17 | dbWriteTable(con, "chat_data", df, overwrite = TRUE)
18 |
19 | ui <- fluidPage(
20 |
21 | fluidRow(
22 | column(width = 6,
23 | textInput("user", "Enter User Name"),
24 | br(),
25 | # add chat ui elements
26 | chat_ui("test3"),
27 | )
28 | )
29 | )
30 |
31 |
32 |
33 | server <- function(input, output, server) {
34 |
35 | # save user name in reactive
36 | user_rv <- reactive({input$user})
37 |
38 | # corresponding server part for id test1
39 | chat_server("test3", db_connection = con,
40 | db_table_name = "chat_data",
41 | chat_user = user_rv
42 | )
43 | }
44 |
45 |
46 | # Run the application
47 | shinyApp(ui = ui, server = server)
48 |
--------------------------------------------------------------------------------
/inst/examples/example_db_update_text.R:
--------------------------------------------------------------------------------
1 |
2 | library(shinyChatR)
3 |
4 | # store db as tempfile. Select different path to store db locally
5 | tempdb <- file.path(tempdir(), "db")
6 |
7 | con <- dbConnect(RSQLite::SQLite(), tempdb)
8 |
9 |
10 | ui <- fluidPage(
11 |
12 | fluidRow(
13 | column(width = 6,
14 | # add chat ui elements
15 | chat_ui("test1"),
16 | )
17 | ),
18 | br(),
19 | fluidRow(
20 | column(width = 6,
21 | # add button to update text value
22 | actionButton("set_value_abc", "Set text to 'abc'"),
23 | )
24 | ),
25 |
26 | )
27 |
28 |
29 | server <- function(input, output, server) {
30 |
31 | # corresponding server part for id test1
32 | chat_server("test1", db_connection = con,
33 | db_table_name = "chat_data",
34 | chat_user = "user1"
35 | )
36 |
37 | observeEvent(input$set_value_abc,{
38 | updateChatTextInput(id = "test1",
39 | value = "abc")
40 | })
41 | }
42 |
43 |
44 | # Run the application
45 | shinyApp(ui = ui, server = server)
46 |
--------------------------------------------------------------------------------
/inst/examples/example_rds.R:
--------------------------------------------------------------------------------
1 |
2 | #library(shinyChatR)
3 |
4 | # # initiate chat data df.
5 | # df <- data.frame(rowid = numeric(),
6 | # user = character(),
7 | # text = character(),
8 | # time = double())
9 |
10 | # save rds file in tempdir. Replace with path to save locally.
11 | test_rds <- file.path(tempdir(), "data2.rds")
12 | # saveRDS(df, test_rds)
13 |
14 | ui <- fluidPage(
15 |
16 | fluidRow(
17 | column(width = 6,
18 | # add chat ui elements
19 | chat_ui("test2"),
20 | )
21 | )
22 | )
23 |
24 | server <- function(input, output, server) {
25 |
26 | # corresponding server part for id test2
27 | chat_server("test2",
28 | rds_path = test_rds,
29 | chat_user = "user2"
30 | )
31 | }
32 |
33 |
34 | # Run the application
35 | shinyApp(ui = ui, server = server)
36 |
--------------------------------------------------------------------------------
/man/CSVConnection.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/CSVConnection.R
3 | \name{CSVConnection}
4 | \alias{CSVConnection}
5 | \title{CSVConnection R6 Class}
6 | \value{
7 | The full dataset
8 |
9 | Save a message to data source
10 | }
11 | \description{
12 | CSVConnection R6 Class
13 |
14 | CSVConnection R6 Class
15 | }
16 | \details{
17 | An R6 class representing a connection to a CSV file for the chat module.
18 | }
19 | \section{Public fields}{
20 | \if{html}{\out{}}
21 | \describe{
22 | \item{\code{csv_path}}{The path to the CSV file.}
23 |
24 | \item{\code{nlast}}{The number of messages to be read in and displayed.
25 |
26 | Initialize the R6 Object}
27 | }
28 | \if{html}{\out{
}}
29 | }
30 | \section{Methods}{
31 | \subsection{Public methods}{
32 | \itemize{
33 | \item \href{#method-CSVConnection-new}{\code{CSVConnection$new()}}
34 | \item \href{#method-CSVConnection-get_data}{\code{CSVConnection$get_data()}}
35 | \item \href{#method-CSVConnection-insert_message}{\code{CSVConnection$insert_message()}}
36 | \item \href{#method-CSVConnection-clone}{\code{CSVConnection$clone()}}
37 | }
38 | }
39 | \if{html}{\out{
}}
40 | \if{html}{\out{}}
41 | \if{latex}{\out{\hypertarget{method-CSVConnection-new}{}}}
42 | \subsection{Method \code{new()}}{
43 | \subsection{Usage}{
44 | \if{html}{\out{}}\preformatted{CSVConnection$new(csv_path, nlast = NULL)}\if{html}{\out{
}}
45 | }
46 |
47 | \subsection{Arguments}{
48 | \if{html}{\out{}}
49 | \describe{
50 | \item{\code{csv_path}}{The path to the csv file.}
51 |
52 | \item{\code{nlast}}{The number of messages to be read-in.}
53 | }
54 | \if{html}{\out{
}}
55 | }
56 | }
57 | \if{html}{\out{
}}
58 | \if{html}{\out{}}
59 | \if{latex}{\out{\hypertarget{method-CSVConnection-get_data}{}}}
60 | \subsection{Method \code{get_data()}}{
61 | Reads the full dataset
62 | \subsection{Usage}{
63 | \if{html}{\out{}}\preformatted{CSVConnection$get_data()}\if{html}{\out{
}}
64 | }
65 |
66 | }
67 | \if{html}{\out{
}}
68 | \if{html}{\out{}}
69 | \if{latex}{\out{\hypertarget{method-CSVConnection-insert_message}{}}}
70 | \subsection{Method \code{insert_message()}}{
71 | \subsection{Usage}{
72 | \if{html}{\out{}}\preformatted{CSVConnection$insert_message(message, user, time)}\if{html}{\out{
}}
73 | }
74 |
75 | \subsection{Arguments}{
76 | \if{html}{\out{}}
77 | \describe{
78 | \item{\code{message}}{The message to be stores}
79 |
80 | \item{\code{user}}{The user who entered the message}
81 |
82 | \item{\code{time}}{The time when message was submitted}
83 | }
84 | \if{html}{\out{
}}
85 | }
86 | }
87 | \if{html}{\out{
}}
88 | \if{html}{\out{}}
89 | \if{latex}{\out{\hypertarget{method-CSVConnection-clone}{}}}
90 | \subsection{Method \code{clone()}}{
91 | The objects of this class are cloneable with this method.
92 | \subsection{Usage}{
93 | \if{html}{\out{}}\preformatted{CSVConnection$clone(deep = FALSE)}\if{html}{\out{
}}
94 | }
95 |
96 | \subsection{Arguments}{
97 | \if{html}{\out{}}
98 | \describe{
99 | \item{\code{deep}}{Whether to make a deep clone.}
100 | }
101 | \if{html}{\out{
}}
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/man/DBConnection.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/DBConnection.R
3 | \name{DBConnection}
4 | \alias{DBConnection}
5 | \title{DBConnection R6 Class}
6 | \value{
7 | The full dataset
8 |
9 | Save a message to data source
10 | }
11 | \description{
12 | DBConnection R6 Class
13 |
14 | DBConnection R6 Class
15 | }
16 | \details{
17 | An R6 class representing a connection to a database for the chat module.
18 | }
19 | \section{Public fields}{
20 | \if{html}{\out{}}
21 | \describe{
22 | \item{\code{connection}}{A database connection object, created using a package such as RSQLite.}
23 |
24 | \item{\code{table}}{The table that contains the chat information.
25 |
26 |
27 | Initialize the R6 Object}
28 | }
29 | \if{html}{\out{
}}
30 | }
31 | \section{Methods}{
32 | \subsection{Public methods}{
33 | \itemize{
34 | \item \href{#method-DBConnection-new}{\code{DBConnection$new()}}
35 | \item \href{#method-DBConnection-get_data}{\code{DBConnection$get_data()}}
36 | \item \href{#method-DBConnection-insert_message}{\code{DBConnection$insert_message()}}
37 | \item \href{#method-DBConnection-clone}{\code{DBConnection$clone()}}
38 | }
39 | }
40 | \if{html}{\out{
}}
41 | \if{html}{\out{}}
42 | \if{latex}{\out{\hypertarget{method-DBConnection-new}{}}}
43 | \subsection{Method \code{new()}}{
44 | \subsection{Usage}{
45 | \if{html}{\out{}}\preformatted{DBConnection$new(connection, table = "chat_data")}\if{html}{\out{
}}
46 | }
47 |
48 | \subsection{Arguments}{
49 | \if{html}{\out{}}
50 | \describe{
51 | \item{\code{connection}}{DB connection}
52 |
53 | \item{\code{table}}{Table name}
54 | }
55 | \if{html}{\out{
}}
56 | }
57 | }
58 | \if{html}{\out{
}}
59 | \if{html}{\out{}}
60 | \if{latex}{\out{\hypertarget{method-DBConnection-get_data}{}}}
61 | \subsection{Method \code{get_data()}}{
62 | Reads the full dataset
63 | \subsection{Usage}{
64 | \if{html}{\out{}}\preformatted{DBConnection$get_data()}\if{html}{\out{
}}
65 | }
66 |
67 | }
68 | \if{html}{\out{
}}
69 | \if{html}{\out{}}
70 | \if{latex}{\out{\hypertarget{method-DBConnection-insert_message}{}}}
71 | \subsection{Method \code{insert_message()}}{
72 | \subsection{Usage}{
73 | \if{html}{\out{}}\preformatted{DBConnection$insert_message(message, user, time)}\if{html}{\out{
}}
74 | }
75 |
76 | \subsection{Arguments}{
77 | \if{html}{\out{}}
78 | \describe{
79 | \item{\code{message}}{The message to be stores}
80 |
81 | \item{\code{user}}{The user who entered the message}
82 |
83 | \item{\code{time}}{The time when message was submitted}
84 | }
85 | \if{html}{\out{
}}
86 | }
87 | }
88 | \if{html}{\out{
}}
89 | \if{html}{\out{}}
90 | \if{latex}{\out{\hypertarget{method-DBConnection-clone}{}}}
91 | \subsection{Method \code{clone()}}{
92 | The objects of this class are cloneable with this method.
93 | \subsection{Usage}{
94 | \if{html}{\out{}}\preformatted{DBConnection$clone(deep = FALSE)}\if{html}{\out{
}}
95 | }
96 |
97 | \subsection{Arguments}{
98 | \if{html}{\out{}}
99 | \describe{
100 | \item{\code{deep}}{Whether to make a deep clone.}
101 | }
102 | \if{html}{\out{
}}
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/man/RDSConnection.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/RDSConnection.R
3 | \name{RDSConnection}
4 | \alias{RDSConnection}
5 | \title{RDSConnection R6 Class}
6 | \value{
7 | The full dataset
8 |
9 | Save a message to data source
10 | }
11 | \description{
12 | RDSConnection R6 Class
13 |
14 | RDSConnection R6 Class
15 | }
16 | \details{
17 | An R6 class representing a connection to a rds file for the chat module.
18 | }
19 | \section{Public fields}{
20 | \if{html}{\out{}}
21 | \describe{
22 | \item{\code{rds_path}}{The path to the rds file.
23 |
24 | Initialize the R6 Object}
25 | }
26 | \if{html}{\out{
}}
27 | }
28 | \section{Methods}{
29 | \subsection{Public methods}{
30 | \itemize{
31 | \item \href{#method-RDSConnection-new}{\code{RDSConnection$new()}}
32 | \item \href{#method-RDSConnection-get_data}{\code{RDSConnection$get_data()}}
33 | \item \href{#method-RDSConnection-insert_message}{\code{RDSConnection$insert_message()}}
34 | \item \href{#method-RDSConnection-clone}{\code{RDSConnection$clone()}}
35 | }
36 | }
37 | \if{html}{\out{
}}
38 | \if{html}{\out{}}
39 | \if{latex}{\out{\hypertarget{method-RDSConnection-new}{}}}
40 | \subsection{Method \code{new()}}{
41 | \subsection{Usage}{
42 | \if{html}{\out{}}\preformatted{RDSConnection$new(rds_path)}\if{html}{\out{
}}
43 | }
44 |
45 | \subsection{Arguments}{
46 | \if{html}{\out{}}
47 | \describe{
48 | \item{\code{rds_path}}{The path to the rds file.}
49 | }
50 | \if{html}{\out{
}}
51 | }
52 | }
53 | \if{html}{\out{
}}
54 | \if{html}{\out{}}
55 | \if{latex}{\out{\hypertarget{method-RDSConnection-get_data}{}}}
56 | \subsection{Method \code{get_data()}}{
57 | Reads the full dataset
58 | \subsection{Usage}{
59 | \if{html}{\out{}}\preformatted{RDSConnection$get_data()}\if{html}{\out{
}}
60 | }
61 |
62 | }
63 | \if{html}{\out{
}}
64 | \if{html}{\out{}}
65 | \if{latex}{\out{\hypertarget{method-RDSConnection-insert_message}{}}}
66 | \subsection{Method \code{insert_message()}}{
67 | \subsection{Usage}{
68 | \if{html}{\out{}}\preformatted{RDSConnection$insert_message(message, user, time)}\if{html}{\out{
}}
69 | }
70 |
71 | \subsection{Arguments}{
72 | \if{html}{\out{}}
73 | \describe{
74 | \item{\code{message}}{The message to be stores}
75 |
76 | \item{\code{user}}{The user who entered the message}
77 |
78 | \item{\code{time}}{The time when message was submitted}
79 | }
80 | \if{html}{\out{
}}
81 | }
82 | }
83 | \if{html}{\out{
}}
84 | \if{html}{\out{}}
85 | \if{latex}{\out{\hypertarget{method-RDSConnection-clone}{}}}
86 | \subsection{Method \code{clone()}}{
87 | The objects of this class are cloneable with this method.
88 | \subsection{Usage}{
89 | \if{html}{\out{}}\preformatted{RDSConnection$clone(deep = FALSE)}\if{html}{\out{
}}
90 | }
91 |
92 | \subsection{Arguments}{
93 | \if{html}{\out{}}
94 | \describe{
95 | \item{\code{deep}}{Whether to make a deep clone.}
96 | }
97 | \if{html}{\out{
}}
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/man/chat_server.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/chat.R
3 | \name{chat_server}
4 | \alias{chat_server}
5 | \title{A chat module for Shiny apps - server}
6 | \usage{
7 | chat_server(
8 | id,
9 | chat_user,
10 | db_connection = NULL,
11 | db_table_name = "chat_data",
12 | rds_path = NULL,
13 | csv_path = NULL,
14 | invalidateDSMillis = 1000,
15 | pretty = TRUE,
16 | nlast = 100
17 | )
18 | }
19 | \arguments{
20 | \item{id}{The id of the module.}
21 |
22 | \item{chat_user}{The user name that should be displayed next to the message.}
23 |
24 | \item{db_connection}{A database connection object, created using the \code{DBI} package. If provided, the chat messages will be stored in a database table.}
25 |
26 | \item{db_table_name}{he name of the database table to use for storing the chat messages. If \code{db_connection} is provided, this parameter is required.}
27 |
28 | \item{rds_path}{The path to an RDS file to use for storing the chat messages. If provided, the chat messages will be stored in an RDS file.}
29 |
30 | \item{csv_path}{The path to an csv file to use for storing the chat messages. If provided, the chat messages will be stored in an csv file.}
31 |
32 | \item{invalidateDSMillis}{The milliseconds to wait before the data source is read again. The default is 1 second.}
33 |
34 | \item{pretty}{Logical that determines if the date should be displayed in a pretty format}
35 |
36 | \item{nlast}{The number of last messages to be read in and displayed}
37 | }
38 | \value{
39 | the reactive values \code{chat_rv} with all the chat information
40 | }
41 | \description{
42 | Creates the server logic for the chat module, which handles adding new messages to the database or RDS file, and retrieving messages to display
43 | }
44 |
--------------------------------------------------------------------------------
/man/chat_ui.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/chat.R
3 | \name{chat_ui}
4 | \alias{chat_ui}
5 | \title{A chat module for Shiny apps - UI}
6 | \usage{
7 | chat_ui(id, ui_title = "", height = "300px", width = "100\%")
8 | }
9 | \arguments{
10 | \item{id}{The id of the module}
11 |
12 | \item{ui_title}{The title of the chat area.}
13 |
14 | \item{height}{The height of the chat display area. Default is 300px.}
15 |
16 | \item{width}{The width of the chat display area.}
17 | }
18 | \description{
19 | Creates the user interface for the chat module, which includes a chat message display area, a text input field for entering new messages, and a send button.
20 | }
21 |
--------------------------------------------------------------------------------
/man/render_msg_divs.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{render_msg_divs}
4 | \alias{render_msg_divs}
5 | \title{Render the messages for the chat}
6 | \usage{
7 | render_msg_divs(texts, users, act_user)
8 | }
9 | \arguments{
10 | \item{texts}{a character vector with the texts}
11 |
12 | \item{users}{a character vector with the users}
13 |
14 | \item{act_user}{a character with the current user (that is using the app)}
15 | }
16 | \value{
17 | The HTML code containing the chat messages
18 | }
19 | \description{
20 | Render the messages for the chat
21 | }
22 |
--------------------------------------------------------------------------------
/man/render_msg_divs2.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{render_msg_divs2}
4 | \alias{render_msg_divs2}
5 | \title{Render the messages for the chat}
6 | \usage{
7 | render_msg_divs2(texts, users, act_user, time, pretty = TRUE)
8 | }
9 | \arguments{
10 | \item{texts}{a character vector with the texts}
11 |
12 | \item{users}{a character vector with the users}
13 |
14 | \item{act_user}{a character with the current user (that is using the app)}
15 |
16 | \item{time}{a datetime object}
17 |
18 | \item{pretty}{a logical that indicates if it should simplify the date}
19 | }
20 | \value{
21 | The HTML code containing the chat messages
22 | }
23 | \description{
24 | Render the messages for the chat
25 | }
26 |
--------------------------------------------------------------------------------
/man/updateChatTextInput.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/chat.R
3 | \name{updateChatTextInput}
4 | \alias{updateChatTextInput}
5 | \title{A function to update the chat textInput}
6 | \usage{
7 | updateChatTextInput(session = getDefaultReactiveDomain(), id, value)
8 | }
9 | \arguments{
10 | \item{session}{The shiny session.}
11 |
12 | \item{id}{The id of the module.}
13 |
14 | \item{value}{The new value that should be shown in the chat textInput.}
15 | }
16 | \description{
17 | Updates the value of the chat textInput
18 | }
19 |
--------------------------------------------------------------------------------
/shinyChatR.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | AutoAppendNewline: Yes
16 | StripTrailingWhitespace: Yes
17 |
18 | BuildType: Package
19 | PackageUseDevtools: Yes
20 | PackageInstallArgs: --no-multiarch --with-keep.source
21 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | # This file is part of the standard setup for testthat.
2 | # It is recommended that you do not modify it.
3 | #
4 | # Where should you do additional test configuration?
5 | # Learn more about the roles of various files in:
6 | # * https://r-pkgs.org/tests.html
7 | # * https://testthat.r-lib.org/reference/test_package.html#special-files
8 |
9 | library(testthat)
10 | library(shinyChatR)
11 |
12 | test_check("shinyChatR")
13 |
--------------------------------------------------------------------------------
/tests/testthat/_snaps/chat.md:
--------------------------------------------------------------------------------
1 | # Chat UI is correct
2 |
3 | Code
4 | chat_ui("test")
5 | Output
6 |
116 |
117 |
--------------------------------------------------------------------------------
/tests/testthat/_snaps/utils.md:
--------------------------------------------------------------------------------
1 | # render_msg_divs works
2 |
3 | Code
4 | render_msg_divs(c("hello", "hello"), c("user1", "user2"), "user4")
5 | Output
6 | [[1]]
7 |
8 |
9 | user1
10 | hello
11 |
12 |
13 |
14 | [[2]]
15 |
16 |
17 | user2
18 | hello
19 |
20 |
21 |
22 |
23 | # render_msg_divs2 works
24 |
25 | Code
26 | render_msg_divs2(texts = c("hello", "hello"), users = c("user1", "user2"),
27 | act_user = "user4", time = as.POSIXct(0, origin = "1960-01-01"))
28 | Output
29 |
30 |
31 |
Friday 1 January
32 |
33 | user1
34 | hello
35 |
36 |
37 |
38 |
Friday 1 January
39 |
40 | user2
41 | hello
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/testthat/test-chat.R:
--------------------------------------------------------------------------------
1 |
2 | test_that("Chat UI is correct", {
3 | expect_snapshot(chat_ui("test"))
4 | })
5 |
6 | test_that("Chat Server with DB works", {
7 | # Create a temporary database for testing
8 | test_db <- tempfile()
9 | con <- DBI::dbConnect(RSQLite::SQLite(), dbname = test_db)
10 | df <- data.frame(rowid = numeric(),
11 | user = character(),
12 | text = character(),
13 | time = double())
14 | DBI::dbWriteTable(con, "chat_messages", df, overwrite = TRUE)
15 |
16 | testServer(chat_server, args = list(db_connection = con,
17 | db_table_name = "chat_messages",
18 | chat_user = "user1"), {
19 | session$setInputs(chatInput = "test_message", chatFromSend = 10)
20 | expect_equal(DBI::dbGetQuery(con, 'SELECT user,text FROM chat_messages'),
21 | data.frame(user = "user1",
22 | text = "test_message"))
23 | })
24 | DBI::dbDisconnect(con)
25 | })
26 |
27 | test_that("Chat Server with rds file", {
28 | test_rds <- tempfile(fileext = "rds")
29 | df <- data.frame(rowid = numeric(),
30 | user = character(),
31 | text = character(),
32 | time = double())
33 | saveRDS(df, test_rds)
34 |
35 | testServer(chat_server, args = list(rds_path = test_rds,
36 | chat_user = "user2"), {
37 | session$setInputs(chatInput = "test_message2", chatFromSend = 20)
38 | expect_equal(readRDS(test_rds)[, c("user", "text")],
39 | data.frame(user = "user2",
40 | text = "test_message2"))
41 | })
42 |
43 | })
44 |
45 |
46 | test_that("Chat Server with csv file", {
47 | test_csv <- tempfile(fileext = "csv")
48 |
49 | testServer(chat_server, args = list(csv_path = test_csv,
50 | chat_user = "user2"), {
51 | session$setInputs(chatInput = "test_message2", chatFromSend = 20)
52 | expect_equal(read.csv(test_csv)[, c("user", "text")],
53 | data.frame(user = "user2",
54 | text = "test_message2"))
55 | })
56 |
57 | })
58 |
59 | test_that("Test updateChatTextInput", {
60 | session <- as.environment(list(
61 | ns = "test1",
62 | sendInputMessage = function(inputId, message) {
63 | session$lastInputMessage = list(id = inputId, message = message)
64 | }
65 | ))
66 | class(session) <- "ShinySession"
67 | res <- updateChatTextInput(session = session, id = "test", value = 1)
68 | expect_equal(res, "test-chatInput")
69 | })
70 |
71 |
--------------------------------------------------------------------------------
/tests/testthat/test-utils.R:
--------------------------------------------------------------------------------
1 | test_that('render_msg_divs works', {
2 | expect_snapshot(render_msg_divs(c("hello", "hello"), c("user1", "user2"), "user4"))
3 | })
4 |
5 |
6 | test_that('render_msg_divs2 works', {
7 | expect_snapshot(render_msg_divs2(texts = c("hello", "hello"),
8 | users = c("user1", "user2"),
9 | act_user = "user4",
10 | time = as.POSIXct(0, origin = "1960-01-01")))
11 | })
12 |
--------------------------------------------------------------------------------
/vignettes/figures/example_chat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/julianschmocker/shinyChatR/f4a84c773ca84300dab51c00aad07da654837ff9/vignettes/figures/example_chat.png
--------------------------------------------------------------------------------
/vignettes/figures/example_chat2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/julianschmocker/shinyChatR/f4a84c773ca84300dab51c00aad07da654837ff9/vignettes/figures/example_chat2.png
--------------------------------------------------------------------------------
/vignettes/path_to_your_database_file:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/julianschmocker/shinyChatR/f4a84c773ca84300dab51c00aad07da654837ff9/vignettes/path_to_your_database_file
--------------------------------------------------------------------------------
/vignettes/shinyChatR.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Getting started with shinyChatR"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{Getting started with shinyChatR}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | ```{r, include = FALSE}
11 | knitr::opts_chunk$set(
12 | collapse = TRUE,
13 | comment = "#>",
14 | eval = FALSE
15 | )
16 | ```
17 |
18 | ```{r setup}
19 | library(shinyChatR)
20 | ```
21 |
22 | # Database connection for storing chat data
23 |
24 | If you are using a database connection to store the chat messages, you will need to initialize the database table before using the chat module. The following example shows an example how to do this using the `DBI` and `RSQLite` packages. Replace `db_file` with the path to your database file. The data will be saved in the table `chat_data`.
25 |
26 | ```{r}
27 | library(DBI)
28 | library(RSQLite)
29 |
30 | db_file <- "path_to_your_database_file"
31 | conn <- dbConnect(RSQLite::SQLite(), db_file)
32 |
33 | # initiate chat table
34 | df <- data.frame(rowid = numeric(),
35 | user = character(),
36 | text = character(),
37 | time = double())
38 | dbWriteTable(conn, "chat_data", df)
39 | ```
40 |
41 | Now you can add the chat module to your app:
42 |
43 | ```{r}
44 | ui <- fluidPage(
45 | chat_ui("test")
46 | )
47 |
48 | server <- function(input, output, server) {
49 | chat_server("test", db_connection = conn,
50 | db_table_name = "chat_data",
51 | chat_user = "user2")
52 | }
53 |
54 | # Run the application
55 | shinyApp(ui = ui, server = server)
56 | ```
57 |
58 | ## Reactive user name
59 |
60 | This example show how the user name can be stored in a reactive. Here the user specifies the name in a textInput field.
61 | ```{r}
62 | ui <- fluidPage(
63 |
64 | fluidRow(
65 | column(width = 6,
66 | # Here the user specifies the user name
67 | textInput("user", "Enter User Name"),
68 | br(),
69 | # add chat ui elements
70 | chat_ui("test_reactive"),
71 | )
72 | )
73 | )
74 | ```
75 |
76 | Then, in the server the user name is save in the reactive `user_rv`. This reactive can be passed into the argument `chat_user`.
77 | ```{r}
78 | server <- function(input, output, server) {
79 |
80 | # save user name in reactive
81 | user_rv <- reactive({input$user})
82 |
83 | # corresponding server part for id test_reactive
84 | chat_server("test_reactive", db_connection = conn,
85 | db_table_name = "chat_data",
86 | chat_user = user_rv
87 | )
88 | }
89 | ```
90 |
91 |
92 | # RDS file for storing chat data
93 |
94 | Also the rds file first needs to be initialized.
95 |
96 | ```{r}
97 | df <- data.frame(rowid = numeric(),
98 | user = character(),
99 | text = character(),
100 | time = double())
101 |
102 | test_rds <- "path_to_rds_file.rds"
103 | saveRDS(df, test_rds)
104 | ```
105 |
106 | Now you can add the chat module to your app:
107 |
108 | ```{r}
109 | test_rds <- "path_to_rds_file.rds"
110 |
111 | ui <- fluidPage(
112 | chat_ui("test2")
113 | )
114 |
115 | server <- function(input, output, server) {
116 | chat_server("test2",
117 | rds_path = test_rds,
118 | chat_user = "user2")
119 | }
120 |
121 | # Run the application
122 | shinyApp(ui = ui, server = server)
123 | ```
124 |
125 | # Update the textInput
126 |
127 | The following example shows how to use updateChatTextInput to update the textInput field from outside of the module.
128 |
129 | ```{r}
130 | # store db as tempfile. Select different path to store db locally
131 | tempdb <- file.path(tempdir(), "db")
132 |
133 | con <- dbConnect(RSQLite::SQLite(), tempdb)
134 |
135 | ui <- fluidPage(
136 |
137 | fluidRow(
138 | column(width = 6,
139 | # add chat ui elements
140 | chat_ui("test1"),
141 | )
142 | ),
143 | br(),
144 | fluidRow(
145 | column(width = 6,
146 | # add button to update text value
147 | actionButton("set_value_abc", "Set text to 'abc'"),
148 | )
149 | ),
150 | )
151 |
152 |
153 | server <- function(input, output, server) {
154 |
155 | # corresponding server part for id test1
156 | chat_server("test1", db_connection = con,
157 | db_table_name = "chat_data",
158 | chat_user = "user1"
159 | )
160 |
161 | observeEvent(input$set_value_abc,{
162 | updateChatTextInput(id = "test1",
163 | value = "abc")
164 | })
165 | }
166 |
167 |
168 | # Run the application
169 | shinyApp(ui = ui, server = server)
170 | ```
171 |
172 |
--------------------------------------------------------------------------------