From 9e5aee3ff7e1d21881630a02a8fd36238e97fd5c Mon Sep 17 00:00:00 2001 From: PRijnbeek Date: Tue, 7 Jan 2025 16:28:44 +0100 Subject: [PATCH] Updated dependencies --- CSVViewer.Rproj | 1 + DESCRIPTION | 7 +- NAMESPACE | 6 ++ R/CSVViewer.R | 26 ++++++ R/Launch.R | 16 ++++ inst/shinyApp/App.R | 196 +++++++++++++++++++++------------------ man/CSVViewer-package.Rd | 23 +++++ 7 files changed, 183 insertions(+), 92 deletions(-) create mode 100644 R/CSVViewer.R create mode 100644 man/CSVViewer-package.Rd diff --git a/CSVViewer.Rproj b/CSVViewer.Rproj index eaa6b81..4dfc464 100644 --- a/CSVViewer.Rproj +++ b/CSVViewer.Rproj @@ -1,4 +1,5 @@ Version: 1.0 +ProjectId: 53708426-6ca8-4daa-82a9-880fe451fb94 RestoreWorkspace: Default SaveWorkspace: Default diff --git a/DESCRIPTION b/DESCRIPTION index 3dd03e6..6f103c2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -13,14 +13,13 @@ BugReports: https://github.com/EHDEN/CSVViewer/issues Depends: R (>= 4.0.0) Imports: - shiny -Suggests: + shiny, nextGenShinyApps, DT, jsonlite, rlist, - knitr, - markdown + markdown, + knitr Encoding: UTF-8 LazyData: true RoxygenNote: 7.3.2 diff --git a/NAMESPACE b/NAMESPACE index 6d24660..063a316 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,3 +2,9 @@ export(launch) export(launch_demo) +import(DT) +import(jsonlite) +import(knitr) +import(markdown) +import(nextGenShinyApps) +import(rlist) diff --git a/R/CSVViewer.R b/R/CSVViewer.R new file mode 100644 index 0000000..36718ed --- /dev/null +++ b/R/CSVViewer.R @@ -0,0 +1,26 @@ +# Copyright 2024 EHDEN Foundation +# +# This file is part of Feasibility +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#' @keywords internal +"_PACKAGE" + +#' @import nextGenShinyApps +#' @import DT +#' @import rlist +#' @import markdown +#' @import knitr +#' @import jsonlite +NULL diff --git a/R/Launch.R b/R/Launch.R index e94b6c1..29b9071 100644 --- a/R/Launch.R +++ b/R/Launch.R @@ -1,3 +1,19 @@ +# Copyright 2024 EHDEN Foundation +# +# This file is part of Feasibility +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + #' Launch the application #' #' @param app_port the port on which the app is available diff --git a/inst/shinyApp/App.R b/inst/shinyApp/App.R index a002b7c..3f4f4fa 100644 --- a/inst/shinyApp/App.R +++ b/inst/shinyApp/App.R @@ -62,8 +62,7 @@ ui <- fluidPage( resize = "both", style = "round" ), - textOutput("status"), - actionButton(inputId = "save", label = "Save Comments") + actionButton(inputId = "save", label = "Save Comments") ) ) ), @@ -75,6 +74,26 @@ ui <- fluidPage( style = "margin-top: 20px;", DTOutput("data_table") ) + # Add a modal dialog for unsaved changes + # tags$div(id = "unsaved_changes_modal", class = "modal fade", tabindex = "-1", role = "dialog", + # div(class = "modal-dialog modal-dialog-centered", role = "document", + # div(class = "modal-content", + # div(class = "modal-header", + # h5(class = "modal-title", "Unsaved Changes"), + # tags$button(type = "button", class = "close", `data-dismiss` = "modal", `aria-label` = "Close", + # span(`aria-hidden` = "true", "×") + # ) + # ), + # div(class = "modal-body", + # p("You have unsaved changes. Do you want to discard them and proceed?") + # ), + # div(class = "modal-footer", + # actionButton(inputId = "confirm_discard", label = "Discard and Proceed"), + # actionButton(inputId = "cancel_discard", label = "Cancel") + # ) + # ) + # ) + # ) ) ) @@ -83,17 +102,6 @@ server <- function(input, output, session) { # Reactive value to store the list of CSV files csv_files <- reactiveVal() - commentsRv <- reactiveValues(changed = FALSE) - loading <- reactiveVal(TRUE) - - output$status <- renderText({ - if (commentsRv$changed && !loading()) { - "Text changed but not saved" - } else { - "Text is saved or unchanged" - } - }) - # Update the list of CSV files when the folder path is changed observeEvent(input$folder, { req(input$folder) @@ -120,10 +128,52 @@ server <- function(input, output, session) { choices = setNames(file_paths, file_labels), # Use filtered file paths and labels selected = if (length(file_paths) > 0) file_paths[1] else NULL ) + + load_selected_csv_file() + loading(FALSE) + print(loading()) } }) + # change the list of CSV files when the show_only_data checkbox is changed + observeEvent(input$show_only_data, { + folder_path <- input$folder + + # Check if folder exists + if (!dir.exists(folder_path)) { + showNotification("The specified folder does not exist.", type = "error") + return() + } + + file_paths_labels <- get_file_paths( + folder_path, + show_only_data = input$show_only_data, + max_depth = 5 + ) + + if (!is.null(file_paths_labels)) { + file_paths <- file_paths_labels$file_paths + file_labels <- file_paths_labels$file_labels + + # Update the reactive value + csv_files(file_paths) + + # Update the selectInput with file names only + updateSelectInput( + session, + "csv_file", + choices = setNames(file_paths, file_labels), + # Use filtered file paths and labels + selected = if (length(file_paths) > 0) + file_paths[1] + else + NULL + ) + } + } + ) + # Display the name of the selected CSV file output$selected_file_name <- renderText({ req(input$csv_file) @@ -151,7 +201,7 @@ server <- function(input, output, session) { req(input$csv_file) selected_file <- input$csv_file req(length(selected_file) == 1) - + # Read the selected CSV file data <- tryCatch( read.csv(selected_file, stringsAsFactors = FALSE), @@ -161,30 +211,13 @@ server <- function(input, output, session) { } ) req(!is.null(data)) - + # Render the data table datatable(data, options = list(scrollX = TRUE, searching = TRUE, pageLength = 50)) }) - # Load the comments from the json if selected file is changed - observeEvent(input$csv_file, { - req(input$csv_file) - selected_file <- input$csv_file - comments_json <- paste0(input$folder,"/comments.json") - - comments <- get_comments_by_filename(comments_json, basename(selected_file)) - - if (!is.null(comments)) { - loading(TRUE) - updateTextAreaInput(session, "comments", value = comments) - loading(FALSE) - } - commentsRv$changed <- FALSE - }) - + # Save the comments to the JSON file observeEvent(input$save, { - - # Retrieve the comments comments <- input$comments @@ -192,60 +225,39 @@ server <- function(input, output, session) { comments_json <- paste0(input$folder,"/comments.json") new_entry <- list( - name = basename(input$csv_file), - comments = comments, - updated = format(Sys.time(), "%A, %B %d, %Y %I:%M:%S %p") + name = basename(input$csv_file), + comments = comments, + updated = format(Sys.time(), "%A, %B %d, %Y %I:%M:%S %p") ) # Write comments to the JSON file update_json_file(comments_json, "files", new_entry, "name") - # Notify the user - commentsRv$changed <- FALSE }) - observeEvent(input$show_only_data, { - folder_path <- input$folder - - # Check if folder exists - if (!dir.exists(folder_path)) { - showNotification("The specified folder does not exist.", type = "error") - return() - } - - file_paths_labels <- get_file_paths( - folder_path, - show_only_data = input$show_only_data, - max_depth = 5 - ) - - if (!is.null(file_paths_labels)) { - file_paths <- file_paths_labels$file_paths - file_labels <- file_paths_labels$file_labels - - # Update the reactive value - csv_files(file_paths) - - # Update the selectInput with file names only - updateSelectInput( - session, - "csv_file", - choices = setNames(file_paths, file_labels), - # Use filtered file paths and labels - selected = if (length(file_paths) > 0) - file_paths[1] - else - NULL - ) - } - } - ) - + # Check with user if unsaved changes to comments when a new file is selected observeEvent(input$csv_file, { - # Update the documentation + load_selected_csv_file() + }) + + # Load the selected CSV file, documentation, and comments + load_selected_csv_file <- function() { + req(input$csv_file) selected_file <- input$csv_file + + # update comments + comments_json <- paste0(input$folder, "/comments.json") + comments <- get_comments_by_filename(comments_json, basename(selected_file)) + + if (!is.null(comments)) { + updateTextAreaInput(session, "comments", value = comments) + } else { + updateTextAreaInput(session, "comments", value = "") + } + + # update documentation description <- get_markdown_by_filename(input$folder, selected_file) - + if (is.null(description)) { output$markdown <- renderUI({ includeMarkdown("**No documentation available for this file.**") @@ -255,17 +267,25 @@ server <- function(input, output, session) { includeMarkdown(description) }) } - }) - - # Detect comments field is changed - observeEvent(input$comments, { - print("triggered") - if (!loading()) { - commentsRv$changed <- TRUE - } else { - commentsRv$changed <- FALSE - } - }) + + # Read the selected CSV file + output$data_table <- renderDT({ + req(length(selected_file) == 1) + + # Read the selected CSV file + data <- tryCatch( + read.csv(selected_file, stringsAsFactors = FALSE), + error = function(e) { + showNotification("Failed to read the CSV file.", type = "error") + return(NULL) + } + ) + req(!is.null(data)) + + # Render the data table + datatable(data, options = list(scrollX = TRUE, searching = TRUE, pageLength = 50)) + }) + } } # Run the application using nextGenShinyApps diff --git a/man/CSVViewer-package.Rd b/man/CSVViewer-package.Rd new file mode 100644 index 0000000..d2ca916 --- /dev/null +++ b/man/CSVViewer-package.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CSVViewer.R +\docType{package} +\name{CSVViewer-package} +\alias{CSVViewer} +\alias{CSVViewer-package} +\title{CSVViewer: Shiny App to view csv files} +\description{ +Shiny App to review csv files and add comments on these files. Documentation for each of the csv files can be added and viewed in the app. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/EHDEN/CSVViewer} + \item Report bugs at \url{https://github.com/EHDEN/CSVViewer/issues} +} + +} +\author{ +\strong{Maintainer}: Peter Rijnbeek \email{p.rijnbeek@ehden.eu} + +} +\keyword{internal}