Nothing
#' Setup Framework (First-Time Configuration)
#'
#' Initializes Framework's global configuration and launches the GUI for
#' first-time setup. This is the recommended entry point for new users.
#'
#' Use this function after installing Framework to:
#' - Set your author name and email
#' - Configure default packages for new projects
#' - Set IDE preferences (VS Code, RStudio)
#' - Configure other global defaults
#'
#' @param port Port number to use (default: 8080)
#' @param browse Automatically open browser (default: TRUE)
#'
#' @return Invisibly returns the plumber server object
#'
#' @examples
#' \donttest{
#' if (FALSE) {
#' # First-time setup
#' framework::setup()
#' }
#' }
#'
#' @seealso [gui()] for launching the GUI without initialization check
#'
#' @export
setup <- function(port = 8080, browse = TRUE) {
# Ensure global config exists
init_global_config()
# Launch GUI directly to settings page
gui(port = port, browse = browse, route = "#/settings/basics")
}
#' Launch Framework GUI
#'
#' Opens a beautiful web-based interface for Framework with documentation,
#' project management, and settings configuration.
#'
#' @param port Port number to use (default: 8080)
#' @param host Host address to bind to. Default "127.0.0.1" for local access only.
#' Use "0.0.0.0" to allow connections from other machines (requires appropriate
#' network security).
#' @param browse Automatically open browser (default: TRUE)
#' @param route Initial route to open (default: NULL for home page)
#'
#' @return Invisibly returns the plumber server object
#'
#' @examples
#' \donttest{
#' if (FALSE) {
#' # Launch the GUI
#' framework::gui()
#'
#' # Launch on specific port
#' framework::gui(port = 8888)
#'
#' # Open directly to settings
#' framework::gui(route = "#/settings/basics")
#'
#' # Run as standalone server (no browser, accessible from network)
#' framework::gui(port = 8080, host = "0.0.0.0", browse = FALSE)
#' }
#' }
#'
#' @seealso [setup()] for first-time configuration
#'
#' @export
gui <- function(port = 8080, host = "127.0.0.1", browse = TRUE, route = NULL) {
# Check if we're in development mode (loaded via devtools::load_all)
# Dev mode has inst/ directory; installed packages flatten inst/ contents to root
is_dev_mode <- FALSE
pkg_path <- find.package("framework")
if (dir.exists(file.path(pkg_path, "inst"))) {
# We're in a development directory structure (inst/ only exists in source)
is_dev_mode <- TRUE
dev_root <- pkg_path
}
# Find GUI assets directory
if (is_dev_mode) {
gui_path <- file.path(dev_root, "inst", "gui")
} else {
gui_path <- system.file("gui", package = "framework")
}
if (gui_path == "" || !dir.exists(gui_path)) {
stop("GUI assets not found. Please rebuild the package with `npm run deploy`.")
}
# Find plumber API file
if (is_dev_mode) {
plumber_file <- file.path(dev_root, "inst", "plumber.R")
} else {
plumber_file <- system.file("plumber.R", package = "framework")
}
if (plumber_file == "" || !file.exists(plumber_file)) {
stop("Plumber API file not found.")
}
# Create plumber API
pr <- plumber::plumber$new(plumber_file)
# Add static file serving filter for GUI assets
pr$filter("static", function(req, res) {
# Only handle non-API requests
if (!grepl("^/api/", req$PATH_INFO)) {
# Determine file path
path <- req$PATH_INFO
if (path == "/" || path == "") {
path <- "/index.html"
}
file_path <- file.path(gui_path, gsub("^/", "", path))
if (file.exists(file_path)) {
# Determine content type
ext <- tools::file_ext(file_path)
content_type <- switch(ext,
html = "text/html",
css = "text/css",
js = "application/javascript",
json = "application/json",
png = "image/png",
jpg = "image/jpeg",
jpeg = "image/jpeg",
gif = "image/gif",
svg = "image/svg+xml",
ico = "image/x-icon",
"application/octet-stream"
)
# Read file
is_binary <- grepl("^image/", content_type) || ext == "ico"
if (is_binary) {
body <- readBin(file_path, "raw", file.info(file_path)$size)
} else {
body <- paste(readLines(file_path, warn = FALSE), collapse = "\n")
}
res$status <- 200
res$setHeader("Content-Type", content_type)
res$body <- body
return(res)
}
}
plumber::forward()
})
# Enable CORS
pr$filter("cors", function(req, res) {
res$setHeader("Access-Control-Allow-Origin", "*")
res$setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
res$setHeader("Access-Control-Allow-Headers", "Content-Type")
if (req$REQUEST_METHOD == "OPTIONS") {
res$status <- 200
return(list())
} else {
plumber::forward()
}
})
# Print startup message
message("\n================================================================")
message("Framework GUI")
message("================================================================")
display_host <- if (host == "0.0.0.0") "localhost" else host
message("Running at: http://", display_host, ":", port)
if (host == "0.0.0.0") {
message("Listening on all interfaces (0.0.0.0)")
}
message("Press Ctrl+C to stop")
message("================================================================\n")
# Open browser if requested
if (browse) {
# Always open localhost in browser, even if binding to 0.0.0.0
browser_host <- if (host == "0.0.0.0") "127.0.0.1" else host
url <- paste0("http://", browser_host, ":", port)
if (!is.null(route)) {
url <- paste0(url, "/", gsub("^/", "", route))
}
browser_opt <- getOption("browser")
if (is.null(browser_opt) || !nzchar(browser_opt)) {
message("Note: No browser configured. Open manually: ", url)
} else {
tryCatch(
utils::browseURL(url),
error = function(e) {
message("Could not open browser. Open manually: ", url)
}
)
}
}
# Run the server (blocking until Ctrl+C)
pr$run(port = port, host = host)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.