From 759e0822a8ba15f6eb6cddbb8b56ffcc4ddcfc68 Mon Sep 17 00:00:00 2001 From: RocketQuack <202538874+Rocket-Quack@users.noreply.github.com> Date: Sat, 28 Feb 2026 00:13:39 +0100 Subject: [PATCH] feat(easy-docker-ui): add stack type and manage stack menus --- scripts/easy-docker/lib/ui/screens/base.sh | 5 +- .../easy-docker/lib/ui/screens/production.sh | 272 +++++++++++++++--- 2 files changed, 241 insertions(+), 36 deletions(-) diff --git a/scripts/easy-docker/lib/ui/screens/base.sh b/scripts/easy-docker/lib/ui/screens/base.sh index e7d0a76f..2b02c3fc 100755 --- a/scripts/easy-docker/lib/ui/screens/base.sh +++ b/scripts/easy-docker/lib/ui/screens/base.sh @@ -74,11 +74,12 @@ render_main_screen() { show_main_menu() { gum choose \ - --height 7 \ + --height 8 \ --header "Choose an action" \ --cursor.foreground 63 \ --selected.foreground 45 \ - "Production setup" \ + "Production Stack" \ + "Development Stack" \ "Environment check" \ "Exit" } diff --git a/scripts/easy-docker/lib/ui/screens/production.sh b/scripts/easy-docker/lib/ui/screens/production.sh index 54f73369..4098d6e0 100755 --- a/scripts/easy-docker/lib/ui/screens/production.sh +++ b/scripts/easy-docker/lib/ui/screens/production.sh @@ -1,25 +1,49 @@ #!/usr/bin/env bash -show_production_setup_menu() { +get_setup_display_label() { + local setup_type="${1}" + + case "${setup_type}" in + development) + printf 'Development' + ;; + production | *) + printf 'Production' + ;; + esac +} + +show_setup_menu() { + local setup_type="${1}" + local setup_label="" local status_text="" render_main_screen 1 >&2 - status_text="$(printf "Production setup\n\nChoose whether to create a new stack or manage an existing one.")" + setup_label="$(get_setup_display_label "${setup_type}")" + status_text="$(printf "%s stack\n\nChoose whether to create a new stack or manage an existing one." "${setup_label}")" render_box_message "${status_text}" "0 2" >&2 gum choose \ --height 8 \ - --header "Production setup actions" \ + --header "${setup_label} stack actions" \ --cursor.foreground 63 \ --selected.foreground 45 \ "Create new stack" \ "Manage existing stacks" \ - "Back to main menu" \ + "Back" \ "Exit and close easy-docker" } +show_production_setup_menu() { + show_setup_menu "production" +} + +show_development_setup_menu() { + show_setup_menu "development" +} + prompt_new_stack_name() { local status_text="" @@ -43,37 +67,139 @@ show_stack_topology_menu() { render_main_screen 1 >&2 stack_name="${stack_dir##*/}" - status_text="$(printf "Stack created: %s\nDirectory: %s\n\nChoose the deployment topology." "${stack_name}" "${stack_dir}")" + status_text="$(printf "Stack created: %s\nDirectory: %s\n\nChoose the deployment topology.\n\n- Single-host: easiest setup on one server.\n- Split services: separate app and infra stacks for more control." "${stack_name}" "${stack_dir}")" render_box_message "${status_text}" "0 2" >&2 gum choose \ - --height 9 \ + --height 8 \ --header "Topology" \ --cursor.foreground 63 \ --selected.foreground 45 \ - "Single-host" \ + "Single-host (recommended)" \ "Split services" \ - "Advanced" \ "Abort wizard to main menu" } -show_single_host_examples() { +show_single_host_proxy_menu() { + local stack_dir="${1}" + local stack_name="" local status_text="" render_main_screen 1 >&2 - status_text="$(printf "Single-host examples\n\n- One server, one compose project.\n- Local DB/Redis/Proxy with app services together.\n- Typical small production VM setup.")" + stack_name="${stack_dir##*/}" + status_text="$(printf "Stack: %s\n\nSingle-host setup (step 1/3)\nChoose the proxy mode.\n\n- Traefik and nginx-proxy run inside compose.\n- Caddy is external and uses the no-proxy compose mode." "${stack_name}")" render_box_message "${status_text}" "0 2" >&2 gum choose \ - --height 7 \ - --header "Single-host" \ + --height 11 \ + --header "Single-host: proxy mode" \ --cursor.foreground 63 \ --selected.foreground 45 \ - "Use this topology" \ + "Traefik (HTTP, built-in proxy)" \ + "Traefik (HTTPS + Let's Encrypt)" \ + "nginx-proxy (HTTP)" \ + "nginx-proxy + acme-companion (HTTPS)" \ + "Caddy (external reverse proxy)" \ + "No reverse proxy (direct :8080)" \ "Back to topology selection" } +show_single_host_database_menu() { + local stack_dir="${1}" + local stack_name="" + local status_text="" + + render_main_screen 1 >&2 + + stack_name="${stack_dir##*/}" + status_text="$(printf "Stack: %s\n\nSingle-host setup (step 2/3)\nChoose the database service." "${stack_name}")" + render_box_message "${status_text}" "0 2" >&2 + + gum choose \ + --height 8 \ + --header "Single-host: database" \ + --cursor.foreground 63 \ + --selected.foreground 45 \ + "MariaDB (recommended)" \ + "PostgreSQL" \ + "Back to topology selection" +} + +show_single_host_redis_menu() { + local stack_dir="${1}" + local stack_name="" + local status_text="" + + render_main_screen 1 >&2 + + stack_name="${stack_dir##*/}" + status_text="$(printf "Stack: %s\n\nSingle-host setup (step 3/3)\nChoose whether Redis services should be included." "${stack_name}")" + render_box_message "${status_text}" "0 2" >&2 + + gum choose \ + --height 8 \ + --header "Single-host: redis" \ + --cursor.foreground 63 \ + --selected.foreground 45 \ + "Include Redis (recommended)" \ + "Skip Redis (experienced users only)" \ + "Back to topology selection" +} + +show_custom_modular_apps_multi_select() { + local stack_dir="${1}" + local back_option_label="${2:-Back to topology selection}" + local stack_name="" + local status_text="" + + render_main_screen 1 >&2 + + stack_name="${stack_dir##*/}" + status_text="$(printf "Stack: %s\n\nCustom modular apps\nSelect one or more options.\nUse Space to toggle and Enter to confirm." "${stack_name}")" + render_box_message "${status_text}" "0 2" >&2 + + gum choose \ + --no-limit \ + --height 10 \ + --header "Custom modular apps" \ + --cursor.foreground 63 \ + --selected.foreground 45 \ + "ERPNext" \ + "CRM" \ + "Custom Git app(s)" \ + "${back_option_label}" +} + +prompt_single_host_env_value() { + local stack_dir="${1}" + local variable_name="${2}" + local guidance_text="${3}" + local placeholder="${4:-}" + local render_context="${5:-1}" + local input_feedback="${6:-}" + local stack_name="" + local status_text="" + + if [ "${render_context}" = "1" ]; then + render_main_screen 1 >&2 + + stack_name="${stack_dir##*/}" + guidance_text="${guidance_text//\\n/$'\n'}" + status_text="$(printf "Stack: %s\n\nConfigure %s\n\n%s" "${stack_name}" "${variable_name}" "${guidance_text}")" + render_box_message "${status_text}" "0 2" >&2 + fi + + if [ -n "${input_feedback}" ]; then + gum style --foreground 214 "${input_feedback}" >&2 + fi + + gum input \ + --header "${variable_name}" \ + --prompt "value> " \ + --placeholder "${placeholder}" +} + show_split_services_examples() { local status_text="" @@ -91,23 +217,6 @@ show_split_services_examples() { "Back to topology selection" } -show_advanced_examples() { - local status_text="" - - render_main_screen 1 >&2 - - status_text="$(printf "Advanced examples\n\n- Managed external DB/Redis.\n- Multiple benches with custom images/tags.\n- GitOps-style rendered compose and custom networks/secrets.")" - render_box_message "${status_text}" "0 2" >&2 - - gum choose \ - --height 7 \ - --header "Advanced" \ - --cursor.foreground 63 \ - --selected.foreground 45 \ - "Use this topology" \ - "Back to topology selection" -} - show_abort_wizard_prompt() { local stack_dir="${1}" local status_text="" @@ -127,12 +236,43 @@ show_abort_wizard_prompt() { "Back to topology selection" } -show_manage_stacks_placeholder() { +show_manage_stacks_menu() { + local setup_type="${1}" + shift + local stack_count="${#}" + local setup_label="" local status_text="" render_main_screen 1 >&2 - status_text="$(printf "Manage existing stacks")" + setup_label="$(get_setup_display_label "${setup_type}")" + if [ "${stack_count}" -eq 1 ]; then + status_text="$(printf "Manage existing %s stacks\n\n1 stack found. Select a stack." "${setup_label}")" + else + status_text="$(printf "Manage existing %s stacks\n\n%s stacks found. Select a stack." "${setup_label}" "${stack_count}")" + fi + + render_box_message "${status_text}" "0 2" >&2 + + gum choose \ + --height 14 \ + --header "Existing stacks" \ + --cursor.foreground 63 \ + --selected.foreground 45 \ + "$@" \ + "Back" \ + "Exit and close easy-docker" +} + +show_manage_stacks_placeholder() { + local setup_type="${1}" + local setup_label="" + local status_text="" + + render_main_screen 1 >&2 + + setup_label="$(get_setup_display_label "${setup_type}")" + status_text="$(printf "Manage existing %s stacks\n\nNo stacks found in .easy-docker/stacks yet." "${setup_label}")" render_box_message "${status_text}" "0 2" >&2 @@ -141,7 +281,71 @@ show_manage_stacks_placeholder() { --header "Manage stacks actions" \ --cursor.foreground 63 \ --selected.foreground 45 \ - "Back to production setup" \ - "Back to main menu" \ + "Back" \ + "Exit and close easy-docker" +} + +show_manage_stack_actions_menu() { + local stack_name="${1}" + local stack_dir="${2}" + local status_text="" + + render_main_screen 1 >&2 + + status_text="$(printf "Manage stack\n\nStack: %s\nDirectory: %s\n\nChoose an action for this stack." "${stack_name}" "${stack_dir}")" + + render_box_message "${status_text}" "0 2" >&2 + + gum choose \ + --height 7 \ + --header "Stack actions" \ + --cursor.foreground 63 \ + --selected.foreground 45 \ + "Apps" \ + "Docker" \ + "Back" \ + "Exit and close easy-docker" +} + +show_manage_stack_apps_menu() { + local stack_name="${1}" + local stack_dir="${2}" + local status_text="" + + render_main_screen 1 >&2 + + status_text="$(printf "Manage stack apps\n\nStack: %s\nDirectory: %s\n\nChoose an app-related action for this stack." "${stack_name}" "${stack_dir}")" + + render_box_message "${status_text}" "0 2" >&2 + + gum choose \ + --height 8 \ + --header "Stack apps actions" \ + --cursor.foreground 63 \ + --selected.foreground 45 \ + "Generate apps.json" \ + "Update custom image apps" \ + "Back" \ + "Exit and close easy-docker" +} + +show_manage_stack_docker_menu() { + local stack_name="${1}" + local stack_dir="${2}" + local status_text="" + + render_main_screen 1 >&2 + + status_text="$(printf "Manage stack docker\n\nStack: %s\nDirectory: %s\n\nChoose a docker-related action for this stack." "${stack_name}" "${stack_dir}")" + + render_box_message "${status_text}" "0 2" >&2 + + gum choose \ + --height 7 \ + --header "Stack docker actions" \ + --cursor.foreground 63 \ + --selected.foreground 45 \ + "Generate docker compose from env" \ + "Back" \ "Exit and close easy-docker" }