mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 16:04:31 +00:00
Separation of concerns: merge silent/UI actions & modularize screens. ProleInstallerBase (actions.py): Created shared base class with 37 deduplicated methods previously duplicated between ProleSilentInstaller and ProleInstaller. Namespace, environment, secret, deployment, port-forward, authority/repair, image, and logging helpers now defined once. Subclasses override _get_input() to bridge their data-access layers. screens.py -> screens/ package (18 mixin modules): Split 10,234-line monolithic screens.py into focused mixin modules: base, navigation, welcome, dependencies, network, environment, database, cluster, services, security, ollama, supabase, docker, build, packaging, deploy, validate, cfg. __init__.py composes ProleInstaller from all mixins and re-exports has_display(), main() for full backward compatibility. All 37 tests pass with no regressions.
109 lines
4.8 KiB
Python
109 lines
4.8 KiB
Python
"""Welcome / splash screen."""
|
|
|
|
import threading
|
|
import time
|
|
import tkinter as tk
|
|
from tkinter import ttk, messagebox, filedialog
|
|
from installer import screen as ui
|
|
|
|
|
|
class WelcomeScreenMixin:
|
|
"""Welcome / splash screen."""
|
|
|
|
def _render_welcome_page(self):
|
|
# Letterhead at top right
|
|
content_width = self.bg_canvas.winfo_width() or 975 # 1300 * 0.75 approx
|
|
right_margin = content_width - 48
|
|
|
|
ui.canvas_text(self, right_margin, 40, 'Prole', fill='#6e6e73', font=('SF Pro Text', 32, 'bold'), anchor='ne')
|
|
ui.canvas_text(self, right_margin, 85, "Infrastructure Automated.", fill='#6e6e73',
|
|
font=('SF Pro Text', 18), anchor='ne')
|
|
|
|
# Welcome title
|
|
self._render_title('Welcome', y=150)
|
|
|
|
welcome_text = (
|
|
"This installer will guide you through the process of setting up the Prole Database and its supporting "
|
|
"infrastructure. We have designed this process to be as automated as possible, ensuring that your "
|
|
"deployment is secure, efficient, and tailored to your specific network environment.\n\n"
|
|
"What to expect:\n"
|
|
"• Network Environment Discovery: We'll scan for existing services like Active Directory and DNS.\n"
|
|
"• System Configuration: Setting up local paths and environment variables.\n"
|
|
"• Dependency Management: Ensuring all required tools (Docker, k3d, etc.) are ready.\n"
|
|
"• Database Initialization: Configuring passwords, Kerberos authentication, and deploying the database cluster.\n\n"
|
|
"We are excited to have you join our community and start building with us. "
|
|
"Welcome to the neighborhood! Let's get started by preparing your system for the Prole experience."
|
|
)
|
|
|
|
ui.canvas_text(self, 48, 220, welcome_text, fill='black', font=('SF Pro Text', 13), width=750)
|
|
|
|
# Ensure footer is updated (Next button visible)
|
|
self.update_footer()
|
|
|
|
def _start_welcome_dependency_scan(self):
|
|
self.splash_scan_running = True
|
|
self.splash_scan_done_at = None
|
|
self.splash_scan_started_at = time.time()
|
|
|
|
deps = list(self.dependencies)
|
|
total = len(deps)
|
|
results = {}
|
|
|
|
def set_status(text: str):
|
|
try:
|
|
if self._splash_status_item is not None:
|
|
# Replace existing text to avoid creating many items
|
|
self.bg_canvas.itemconfig(self._splash_status_item, text=text)
|
|
except Exception:
|
|
pass
|
|
|
|
def worker():
|
|
missing_names = []
|
|
for idx, dep in enumerate(deps, start=1):
|
|
try:
|
|
ok, location, version = self.get_dep_info(dep)
|
|
except Exception:
|
|
ok, location, version = False, None, None
|
|
results[dep['id']] = (ok, location, version)
|
|
# Update status text progressively
|
|
if ok:
|
|
txt = f"[{idx}/{total}] {dep['name']}: Installed"
|
|
else:
|
|
txt = f"[{idx}/{total}] {dep['name']}: Not installed"
|
|
missing_names.append(dep['name'])
|
|
self.safe_after(lambda s=txt: set_status(s))
|
|
# tiny sleep to keep UI responsive without being too fast
|
|
try:
|
|
time.sleep(0.02)
|
|
except Exception:
|
|
pass
|
|
|
|
# Final message
|
|
final_msg = 'All dependencies installed.' if not missing_names else (
|
|
'Preparing to install ... ' + ', '.join(missing_names)
|
|
)
|
|
def on_done():
|
|
set_status(final_msg)
|
|
self.splash_scan_running = False
|
|
self.splash_scan_done_at = time.time()
|
|
# Re-evaluate footer to potentially show Next
|
|
self.update_footer()
|
|
# Important: schedule a follow-up refresh slightly after the debounce window
|
|
# so the Next button becomes visible without requiring further UI events.
|
|
self.safe_after(self.update_footer, delay=600)
|
|
self.safe_after(on_done)
|
|
|
|
t = threading.Thread(target=worker, daemon=True)
|
|
t.start()
|
|
# Failsafe refresh slightly after the 8s gating window in case no UI events fire.
|
|
self.safe_after(self.update_footer, delay=9000)
|
|
|
|
def _create_page_welcome(self):
|
|
f = self._page_container()
|
|
ttk.Label(f, text='Welcome to Prole', style='Title.TLabel').pack(anchor='w', padx=24, pady=(24, 6))
|
|
msg = (
|
|
'Thanks for joining Prole. We will prepare your system and install the software needed to build and run Prole.'
|
|
)
|
|
ttk.Label(f, text=msg, style='Body.TLabel', wraplength=800, justify='left').pack(anchor='w', padx=24)
|
|
# self._register_page('welcome', f)
|