From a9bbaf4504d0908270b935076b59c0b2cf29efba Mon Sep 17 00:00:00 2001 From: madeliri Date: Wed, 22 Apr 2026 18:27:39 +0300 Subject: [PATCH] feat: task_module --- app.R | 264 ++++++++++++++++++++++++++++++++++++- modules/db.R | 2 +- modules/scheme_generator.R | 16 ++- 3 files changed, 278 insertions(+), 4 deletions(-) diff --git a/app.R b/app.R index bd3b55e..e941659 100644 --- a/app.R +++ b/app.R @@ -72,6 +72,7 @@ ui <- page_sidebar( uiOutput("status_message"), textOutput("status_message2"), uiOutput("display_log"), + actionButton("shieesh", "Задачи: нет активных"), position = "left", open = list(mobile = "always") ), @@ -80,6 +81,7 @@ ui <- page_sidebar( # init auth ======================= if (AUTH_ENABLED) { + # shinymanager::set_labels("en", "Please authenticate" = "scheme()") ui <- ui |> shinymanager::secure_app( @@ -155,9 +157,11 @@ server <- function(input, output, session) { # Create a reactive values object to store the input data values <- reactiveValues( data = NULL, + tasks_data = NULL, main_key = NULL, nested_key = NULL, - nested_form_id = NULL + nested_form_id = NULL, + tasks_id_selector = NULL ) scheme <- reactiveVal(enabled_schemes[1]) # наименование выбранной схемы @@ -228,7 +232,7 @@ server <- function(input, output, session) { # updating forms with loaded data utils$update_forms_with_data( - form_id = x_id, + form_id = x_id, form_type = x_type, value = df[[x_id]], scheme = mhcs()$get_scheme(table_name), @@ -863,6 +867,8 @@ server <- function(input, output, session) { values$main_key <- input$load_data_key_selector main_form_is_empty(FALSE) + update_task_button_count(con) + log_action_to_db("loading data", values$main_key, con = con) removeModal() @@ -1224,6 +1230,260 @@ server <- function(input, output, session) { DBI::dbWriteTable(con, "log", action_row, append = TRUE) } + # TASKS --------------------------------------- + ## show button watcher ------------------------- + observeEvent(input$shieesh, { + + con <- db$make_db_connection(scheme(),"nested_tables") + on.exit(db$close_db_connection(con, "nested_tables"), add = TRUE) + + values$tasks_data <- if ("tasks" %in% DBI::dbListTables(con)) { + DBI::dbGetQuery(con, glue::glue("SELECT * FROM tasks WHERE task_main_key = '{values$main_key}'")) |> + dplyr::mutate(dplyr::across(c("task_datetime_created", "task_datetime_last_updated", "task_datetime_completed"), as.POSIXct)) + } else { + get_default_task() + } + + if (nrow(values$tasks_data) == 0) { + values$tasks_data <- get_default_task() + } + + values$tasks_id_selector <- NULL + show_modal_for_tasks() + + }) + + show_modal_for_tasks <- function() { + + tasks_selector <- values$tasks_data |> + dplyr::filter(task_status != "completed") |> + dplyr::pull(task_id) + + tasks_selector <- unique(c(values$tasks_id_selector, tasks_selector)) + tasks_selector <- sort(tasks_selector) + + if (length(values$tasks_id_selector) == 0) { + values$tasks_id_selector <- if (length(tasks_selector) == 0) NULL else tasks_selector[[1]] + } + + # ui + # очень большой костыль + subroup_scheme <- mhcs()$get_scheme("tasks") |> + dplyr::filter(form_id != "dummy") + + tab <- bslib::nav_panel( + title = "no name provided", + purrr::pmap( + .l = dplyr::distinct(subroup_scheme, form_id, form_label, form_type), + .f = utils$render_forms, + main_scheme = subroup_scheme + ) + ) + + ui <- layout_sidebar( + sidebar = tagList( + selectizeInput("hhhhhhh", label = "what", choices = tasks_selector, selected = values$tasks_id_selector), + actionButton("tasks_create_new_task", "new_task"), + actionButton("tasks_add_autoreview", "add autotask"), + actionButton("tasks_DT_VIEW", "DT") + ), + tab + ) + + showModal(modalDialog( + ui, + size = "l", + footer = tagList( + actionButton("tasks_saving_button", "сохранить изменения") + ), + easyClose = TRUE + )) + } + + observeEvent(input$hhhhhhh, { + req(input$hhhhhhh) + req(values$tasks_id_selector) + + # выбранный ключ в форме - перемещаем в RV + values$tasks_id_selector <- input$hhhhhhh + + }) + + observeEvent(values$tasks_id_selector, { + + df <- values$tasks_data |> + dplyr::filter(task_id == values$tasks_id_selector) + + load_data_to_form( + df = df, + table_name = "tasks", + mhcs() + ) + }) + + ## saving button watcher ------------------------------ + observeEvent(input$tasks_saving_button, { + + con <- db$make_db_connection(scheme(),"tasks_saving_button") + on.exit(db$close_db_connection(con, "tasks_saving_button"), add = TRUE) + + id_and_types_list <- schms$example_of_scheme$get_id_type_list("tasks") + input_types <- unname(id_and_types_list) + input_ids <- names(id_and_types_list) + + exported_values <- purrr::map2( + .x = input_ids, + .y = input_types, + .f = \(x_id, x_type) { + + input_d <- input[[x_id]] + + # return empty if 0 element + if (length(input_d) == 0) { + return(utils$get_empty_data(x_type)) + } else { + input_d + } + } + ) + + exported_df <- setNames(exported_values, input_ids) |> + as_tibble() + + df <- values$tasks_data + + df[df$task_id == values$tasks_id_selector,]$task_status <- exported_df$task_status + df[df$task_id == values$tasks_id_selector,]$task_title <- exported_df$task_title + df[df$task_id == values$tasks_id_selector,]$task_description <- exported_df$task_description + df[df$task_id == values$tasks_id_selector,]$task_due_date <- exported_df$task_due_date + df[df$task_id == values$tasks_id_selector,]$task_user_last_updated <- ifelse(AUTH_ENABLED, res_auth$user, "anonymous") + df[df$task_id == values$tasks_id_selector,]$task_datetime_last_updated <- Sys.time() + + if (exported_df$task_status == "completed") { + df[df$task_id == values$tasks_id_selector,]$task_user_completed <- ifelse(AUTH_ENABLED, res_auth$user, "anonymous") + df[df$task_id == values$tasks_id_selector,]$task_datetime_completed <- Sys.time() + } + + values$tasks_data <- df + + if ("tasks" %in% DBI::dbListTables(con)) { + query <- glue::glue(" + DELETE + FROM tasks + WHERE task_main_key = '{values$main_key}' + ") + DBI::dbExecute(con, query) + } + + DBI::dbWriteTable(con, "tasks", df, append = TRUE) + + update_task_button_count(con) + showNotification("Задача успешно создана/обновлена", type = "message") + + tasks_selector <- values$tasks_data |> + dplyr::filter(task_status != "completed") |> + dplyr::pull(task_id) + + selector <- ifelse(!values$tasks_id_selector %in% tasks_selector, tasks_selector[1], values$tasks_id_selector) + + updateSelectInput(inputId = "hhhhhhh", choices = tasks_selector, selected = selector) + + }) + + observeEvent(input$tasks_DT_VIEW, { + + output$dt_tasks <- DT::renderDataTable( + DT::datatable( + values$tasks_data, + caption = 'Table 1: This is a simple caption for the table.', + rownames = FALSE, + # colnames = col_types |> dplyr::pull(form_id, form_label), + extensions = c('KeyTable', "FixedColumns"), + # editable = 'cell', + selection = "none", + options = list( + dom = 'tip', + scrollX = TRUE, + fixedColumns = list(leftColumns = 1), + keys = TRUE + ) + ) |> + DT::formatDate(c("task_datetime_created", "task_datetime_completed", "task_datetime_last_updated"), "toLocaleDateString", params = list('ru-RU')) + ) + + showModal(modalDialog( + DT::dataTableOutput("dt_tasks"), + size = "xl", + # footer = tagList( + # actionButton("nested_form_dt_save", "сохранить изменения") + # ), + easyClose = TRUE + )) + + }) + + ## functions ---------------------------------- + get_default_task <- function() { + + tibble::tibble( + task_id = paste0(format(Sys.time(), "%Y%m%d%H%M%S"), "_", values$main_key), + task_main_key = values$main_key, + task_status = "active", + task_title = "new task", + task_description = "description", + task_due_date = NA, + task_user_created = ifelse(AUTH_ENABLED, res_auth$user, "anonymous"), + task_datetime_created = Sys.time(), + task_user_last_updated = NA, + task_datetime_last_updated = NA, + task_user_completed = NA, + task_datetime_completed = NA + ) + } + + observeEvent(input$tasks_create_new_task, { + new_task <- get_default_task() + + values$tasks_data <- rbind(values$tasks_data, new_task) + values$tasks_id_selector <- new_task$task_id + + tasks_selector <- values$tasks_data |> + dplyr::filter(task_status != "completed") |> + dplyr::pull(task_id) + + updateSelectInput(inputId = "hhhhhhh", choices = tasks_selector, selected = values$tasks_id_selector) + }) + + observeEvent(input$tasks_add_autoreview, { + new_task <- get_default_task() + + new_task$task_title <- "autoreview" + new_task$task_description <- "напоминание об актуализации данных" + new_task$task_due_date <- Sys.Date() + 28 + + values$tasks_data <- rbind(values$tasks_data, new_task) + values$tasks_id_selector <- new_task$task_id + + tasks_selector <- values$tasks_data |> + dplyr::filter(task_status != "completed") |> + dplyr::pull(task_id) + + updateSelectInput(inputId = "hhhhhhh", choices = tasks_selector, selected = values$tasks_id_selector) + }) + + + update_task_button_count <- function(con) { + if ("tasks" %in% DBI::dbListTables(con)) { + tasks_num <- DBI::dbGetQuery(con, glue::glue("SELECT COUNT ('task_id') FROM tasks WHERE task_main_key = '{values$main_key}' AND task_status = 'active'")) |> + pull() + if (tasks_num > 0) { + updateActionButton(inputId = "shieesh", label = paste("активных задач:", tasks_num)) + } else { + updateActionButton(inputId = "shieesh", label = "Задачи: нет активных") + } + } + } + # КРАТКАЯ СВОДКА ПРО ЛОГГИНГ ------------------ # observe({ diff --git a/modules/db.R b/modules/db.R index ffd4db3..14a6e2a 100644 --- a/modules/db.R +++ b/modules/db.R @@ -3,7 +3,7 @@ #' @description Function to open connection to db, disigned to easy dubugging. #' @param where text mark to distingiush calss make_db_connection = function(scheme, where = "") { - if (getOption("APP.DEBUG", FALSE)) message("=== DB CONNECT ", where) + DBI::dbConnect(RSQLite::SQLite(), fs::path( config::get("form_app_configure_path"), "db", diff --git a/modules/scheme_generator.R b/modules/scheme_generator.R index 58a07f9..b01dcee 100644 --- a/modules/scheme_generator.R +++ b/modules/scheme_generator.R @@ -40,6 +40,19 @@ scheme_R6 <- R6::R6Class( } ) + # отдельно для тасков + private$schemes_list[["tasks"]] <- tibble::tribble( + ~ form_id, ~form_type, ~form_label, ~form_description, ~choices, + "dummy", "text", "dummy", "dummy", NA, + "task_status", "select_one", "Статус задачи", NA, "active", + "task_status", "select_one", "Статус задачи", NA, "completed", + "task_status", "select_one", "Статус задачи", NA, "deleted", + "task_title", "text", "Название задачи", NA, NA, + "task_description", "text", "Описание задачи", "краткое описание", NA, + "task_due_date", "date", "Дата выполнения задачи", "YE DJN", NA, + ) |> + dplyr::mutate(condition = NA) + # extract main key private$main_key_id <- self$get_key_id("main") @@ -78,6 +91,7 @@ scheme_R6 <- R6::R6Class( get_scheme = function(table_name) { private$schemes_list[[table_name]] }, + ## с полями имеющие значение ------- get_scheme_with_values_forms = function(table_name) { private$schemes_list[[table_name]] |> @@ -117,7 +131,7 @@ scheme_R6 <- R6::R6Class( nested_forms_names = NA, bslib_rendered_ui = NA, excluded_types = c("nested_forms", "description", "description_header"), - reserved_table_names = c("meta", "log", "main"), + reserved_table_names = c("meta", "log", "main", "tasks"), load_scheme_from_xlsx = function(sheet_name) {