feat: add interactive setup wizard for first-run configuration
Implement a comprehensive setup wizard to improve onboarding and configuration experience for both personal and server deployments. Key features: - Interactive wizard with profile selection (personal/server/custom) - Quick setup mode with sensible defaults - First-run detection with helpful welcome message - Directory configuration with validation - Server OAuth/JWT configuration with auto-generation - Environment file creation for server deployments - Template generators for systemd service and env files New commands: - opal setup # Interactive wizard - opal setup --quick # Quick setup with defaults - opal setup --profile # Use specific profile - opal setup --show-systemd # Show systemd template - opal setup --show-env # Show environment file template Implementation: - internal/wizard/prompts.go: Reusable prompt utilities - internal/wizard/profiles.go: Profile definitions and templates - cmd/setup.go: Main setup command implementation - cmd/root.go: First-run detection and welcome message - internal/engine/config.go: ConfigExists() and IsFirstRun() helpers User experience: - On first run, shows welcome message suggesting 'opal setup' - Non-intrusive - creates defaults automatically if skipped - Wizard guides through all configuration options - Server setup includes OAuth/JWT configuration - Environment file created with proper permissions (0600) - Clear next steps displayed after completion
This commit is contained in:
+23
-1
@@ -31,7 +31,7 @@ var (
|
||||
var commandNames = []string{
|
||||
"add", "done", "modify", "delete",
|
||||
"start", "stop", "count", "projects", "tags",
|
||||
"info", "edit", "server", "sync", "reports",
|
||||
"info", "edit", "server", "sync", "reports", "setup",
|
||||
}
|
||||
|
||||
// Report names (dynamically populated)
|
||||
@@ -224,6 +224,11 @@ func init() {
|
||||
}
|
||||
|
||||
func initializeApp() {
|
||||
// Skip initialization for commands that handle their own setup
|
||||
if len(os.Args) > 1 && os.Args[1] == "setup" {
|
||||
return
|
||||
}
|
||||
|
||||
// Set directory overrides from flags if provided
|
||||
if configDirFlag != "" {
|
||||
engine.SetConfigDirOverride(configDirFlag)
|
||||
@@ -232,6 +237,9 @@ func initializeApp() {
|
||||
engine.SetDataDirOverride(dataDirFlag)
|
||||
}
|
||||
|
||||
// Check for first run (before initializing DB/config)
|
||||
isFirstRun := engine.IsFirstRun()
|
||||
|
||||
// Initialize database
|
||||
if err := engine.InitDB(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error initializing database: %v\n", err)
|
||||
@@ -243,4 +251,18 @@ func initializeApp() {
|
||||
fmt.Fprintf(os.Stderr, "Error loading config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Show first-run message after config is created
|
||||
if isFirstRun {
|
||||
showFirstRunMessage()
|
||||
}
|
||||
}
|
||||
|
||||
func showFirstRunMessage() {
|
||||
fmt.Fprintln(os.Stderr, "")
|
||||
fmt.Fprintln(os.Stderr, "👋 Welcome to Opal Task Manager!")
|
||||
fmt.Fprintln(os.Stderr, "")
|
||||
fmt.Fprintln(os.Stderr, "Default configuration created. To customize your setup,")
|
||||
fmt.Fprintln(os.Stderr, "run: opal setup")
|
||||
fmt.Fprintln(os.Stderr, "")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user