add homekeeper stack

This commit is contained in:
2026-07-06 19:25:38 +02:00
commit 58983e6855
90 changed files with 6816 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
screen_colonies_ui <- function(id) {
ns <- NS(id)
shiny::tagList(
shiny::uiOutput(ns("status_filters")),
shiny::uiOutput(ns("cards")),
shiny::br(),
shiny::div(class = "d-flex gap-2 mb-2",
shiny::actionButton(ns("quick_insp_btn"),
shiny::tagList(shiny::icon("bolt"), " Schnelldurchsicht"),
class = "btn btn-outline-primary w-100"
),
shiny::actionButton(ns("bulk_action_btn"),
shiny::tagList(shiny::icon("layer-group"), " Sammelmaßnahme"),
class = "btn btn-outline-secondary w-100"
)
),
shiny::div(class = "d-flex gap-2 mb-2",
shiny::actionButton(ns("lineage_btn"),
shiny::tagList(shiny::icon("sitemap"), " Stammbaum"),
class = "btn btn-outline-secondary w-100"
)
),
shiny::actionButton(ns("add_btn"), shiny::tagList(shiny::icon("plus"), " Neues Volk"),
class = "add-dashed btn", style = "width:100%;min-height:80px"
)
)
}
screen_colonies_server <- function(id, db, nav) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
reload <- reactiveVal(0)
status_filter <- reactiveVal("")
colonies <- reactive({
req(nav$apiary_id)
reload()
db_colonies_list(db, apiary_id = nav$apiary_id, include_closed = FALSE)
})
output$status_filters <- renderUI({
statuses <- c("Alle" = "", COLONY_STATUSES[names(COLONY_STATUSES) != "Eingegangen"])
shiny::div(class = "d-flex gap-2 mb-3 flex-wrap",
lapply(seq_along(statuses), function(i) {
val <- statuses[[i]]
active <- identical(status_filter(), val)
shiny::actionButton(
ns(paste0("sf_", i)), names(statuses)[i],
class = if (active) "btn btn-primary btn-sm" else "btn btn-outline-secondary btn-sm"
)
})
)
})
observe({
statuses <- c("Alle" = "", COLONY_STATUSES[names(COLONY_STATUSES) != "Eingegangen"])
lapply(seq_along(statuses), function(i) {
local({
li <- i; val <- statuses[[i]]
observeEvent(input[[paste0("sf_", li)]], status_filter(val), ignoreInit = TRUE)
})
})
})
filtered <- reactive({
cols <- colonies()
sf <- status_filter()
if (!is.null(sf) && sf != "") cols[cols$status == sf, ] else cols
})
output$cards <- renderUI({
cols <- filtered()
if (nrow(cols) == 0) return(shiny::p(class = "text-muted", "Keine Völker gefunden."))
lapply(seq_len(nrow(cols)), function(i) {
row <- cols[i, ]
days_ago <- if (!is.na(row$last_inspection_date)) {
d <- as.integer(Sys.Date() - as.Date(row$last_inspection_date))
if (d == 0) "heute" else if (d == 1) "gestern" else paste0("vor ", d, " Tagen")
} else "keine Durchsicht"
shiny::div(
class = "card tap-card mb-2",
onclick = sprintf("Shiny.setInputValue('%s', %d, {priority:'event'})",
ns("select"), row$id),
bslib::card_body(
class = "d-flex justify-content-between align-items-center py-2",
shiny::div(
shiny::tags$strong(row$name),
shiny::tags$p(class = "text-muted small mb-0", days_ago)
),
shiny::HTML(colony_status_badge(row$status))
)
)
})
})
observeEvent(input$select, {
nav$colony_id <- input$select
nav$screen <- "colony"
})
observeEvent(input$quick_insp_btn, { nav$screen <- "quick_inspection" })
observeEvent(input$bulk_action_btn, { nav$screen <- "bulk_action" })
observeEvent(input$lineage_btn, { nav$screen <- "lineage" })
# ---- Add colony modal ---------------------------------------------------
observeEvent(input$add_btn, {
cols <- db_colonies_list(db, include_closed = FALSE)
shiny::showModal(shiny::modalDialog(
title = "Neues Volk",
footer = shiny::tagList(
shiny::modalButton("Abbrechen"),
shiny::actionButton(ns("confirm_add"), "Anlegen", class = "btn-primary")
),
shiny::textInput(ns("new_name"), "Name *"),
shiny::selectInput(ns("new_status"), "Status",
choices = COLONY_STATUSES[names(COLONY_STATUSES) != "Eingegangen"],
selected = "wirtschaftsvolk"
),
shiny::selectInput(ns("new_parent"), "Muttervolk (optional)",
choices = c("" = "", setNames(cols$id, cols$name))
),
shiny::textAreaInput(ns("new_notes"), "Notizen", rows = 2)
))
})
observeEvent(input$confirm_add, {
if (nchar(trimws(input$new_name)) == 0) {
shiny::showNotification("Bitte einen Namen eingeben.", type = "warning", duration = 3)
return()
}
req(nav$apiary_id)
parent <- if (!is.null(input$new_parent) && input$new_parent != "")
as.integer(input$new_parent) else NA
db_colonies_insert(db,
name = trimws(input$new_name),
apiary_id = as.integer(nav$apiary_id),
status = input$new_status,
parent_colony_id = parent,
notes = input$new_notes
)
shiny::removeModal(); reload(reload() + 1L)
})
})
}