diff --git a/internal/gui/gui.go b/internal/gui/gui.go
index 0418832..86763d2 100644
--- a/internal/gui/gui.go
+++ b/internal/gui/gui.go
@@ -15,6 +15,7 @@ import (
"fmt"
"os"
"os/exec"
+ "strings"
"sync"
"time"
@@ -231,6 +232,13 @@ func formPhase(cfg config.Config, runCfg runner.RunConfig, cfgPath string) formR
// Phase 2 – Live run view
// --------------------------------------------------------------------------
+// stepIndicator tracks a step's label and blink state.
+type stepIndicator struct {
+ label *walk.Label
+ stepID string
+ status string // "pending", "running", "ok", "error", "skipped", "cancelled"
+}
+
func runPhase(runCfg runner.RunConfig, steps []runner.Step) []runner.Result {
var (
mw *walk.MainWindow
@@ -239,6 +247,21 @@ func runPhase(runCfg runner.RunConfig, steps []runner.Step) []runner.Result {
cancelFn context.CancelFunc
)
+ // Build step indicator labels (one per step, in order)
+ indicators := make([]stepIndicator, len(steps))
+ stepIndex := make(map[string]int, len(steps)) // stepID → index
+ indWidgets := make([]Widget, len(steps))
+ for i, s := range steps {
+ indicators[i] = stepIndicator{stepID: s.ID, status: "pending"}
+ stepIndex[s.ID] = i
+ indWidgets[i] = Label{
+ AssignTo: &indicators[i].label,
+ Text: s.Num + " \u00b7",
+ Font: Font{Family: "Consolas", PointSize: 9},
+ MinSize: Size{Width: 38},
+ }
+ }
+
if err := (MainWindow{
AssignTo: &mw,
Title: "xetup \u2014 probiha instalace",
@@ -246,13 +269,18 @@ func runPhase(runCfg runner.RunConfig, steps []runner.Step) []runner.Result {
Layout: VBox{},
Children: []Widget{
Label{AssignTo: &statusLbl, Text: "Spoustim..."},
+ // Step progress strip
+ Composite{
+ Layout: HBox{MarginsZero: true},
+ Children: indWidgets,
+ },
HSeparator{},
TextEdit{
AssignTo: &logTE,
ReadOnly: true,
VScroll: true,
Font: Font{Family: "Consolas", PointSize: 9},
- MinSize: Size{Height: 590},
+ MinSize: Size{Height: 530},
},
HSeparator{},
Composite{
@@ -274,6 +302,29 @@ func runPhase(runCfg runner.RunConfig, steps []runner.Step) []runner.Result {
return nil
}
+ // updateIndicator refreshes label text and color — call inside Synchronize.
+ updateIndicator := func(idx int) {
+ ind := &indicators[idx]
+ s := steps[idx]
+ switch ind.status {
+ case "running":
+ ind.label.SetText(s.Num + " \u25ba") // ►
+ ind.label.SetTextColor(walk.RGB(30, 144, 255)) // dodger blue
+ case "ok":
+ ind.label.SetText(s.Num + " \u2713") // ✓
+ ind.label.SetTextColor(walk.RGB(0, 180, 0))
+ case "error":
+ ind.label.SetText(s.Num + " \u2717") // ✗
+ ind.label.SetTextColor(walk.RGB(220, 50, 50))
+ case "skipped", "cancelled":
+ ind.label.SetText(s.Num + " \u2013") // –
+ ind.label.SetTextColor(walk.RGB(140, 140, 140))
+ default:
+ ind.label.SetText(s.Num + " \u00b7") // ·
+ ind.label.SetTextColor(walk.RGB(180, 180, 180))
+ }
+ }
+
var (
mu sync.Mutex
results []runner.Result
@@ -283,7 +334,6 @@ func runPhase(runCfg runner.RunConfig, steps []runner.Step) []runner.Result {
ctx, cancel := context.WithCancel(context.Background())
cancelFn = cancel
- // Cancel running scripts when user closes the window.
mw.Closing().Attach(func(_ *bool, _ walk.CloseReason) {
cancelFn()
})
@@ -295,11 +345,26 @@ func runPhase(runCfg runner.RunConfig, steps []runner.Step) []runner.Result {
logTE.AppendText(l.Text + "\r\n")
})
},
+ func(step runner.Step) {
+ mw.Synchronize(func() {
+ statusLbl.SetText(fmt.Sprintf(
+ "Krok %s \u2013 %s...", step.Num, step.Name,
+ ))
+ if idx, ok := stepIndex[step.ID]; ok {
+ indicators[idx].status = "running"
+ updateIndicator(idx)
+ }
+ })
+ },
func(res runner.Result) {
mw.Synchronize(func() {
statusLbl.SetText(fmt.Sprintf(
"Krok %s \u2013 %s: %s", res.Step.Num, res.Step.Name, res.Status,
))
+ if idx, ok := stepIndex[res.Step.ID]; ok {
+ indicators[idx].status = strings.ToLower(res.Status)
+ updateIndicator(idx)
+ }
})
},
)
@@ -316,8 +381,8 @@ func runPhase(runCfg runner.RunConfig, steps []runner.Step) []runner.Result {
}()
mw.Run()
- cancel() // stop scripts if window was closed by user
- <-done // wait for goroutine to exit cleanly
+ cancel()
+ <-done
mu.Lock()
defer mu.Unlock()
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 4bec1d8..950bf5c 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -141,15 +141,17 @@ type LogLine struct {
// Runner executes deployment steps sequentially.
type Runner struct {
- cfg RunConfig
- onLog func(LogLine)
- onResult func(Result)
- cancel context.CancelFunc
+ cfg RunConfig
+ onLog func(LogLine)
+ onStepStart func(Step)
+ onResult func(Result)
+ cancel context.CancelFunc
}
// New creates a Runner. onLog is called for each output line, onResult after each step.
-func New(cfg RunConfig, onLog func(LogLine), onResult func(Result)) *Runner {
- return &Runner{cfg: cfg, onLog: onLog, onResult: onResult}
+// onStepStart (optional) is called immediately before a step's script is launched.
+func New(cfg RunConfig, onLog func(LogLine), onStepStart func(Step), onResult func(Result)) *Runner {
+ return &Runner{cfg: cfg, onLog: onLog, onStepStart: onStepStart, onResult: onResult}
}
// Run executes enabled steps sequentially. Blocks until done or context cancelled.
@@ -170,6 +172,9 @@ func (r *Runner) Run(ctx context.Context, steps []Step) []Result {
continue
}
+ if r.onStepStart != nil {
+ r.onStepStart(step)
+ }
start := time.Now()
err := r.runScript(ctx, step, cfgArg)
elapsed := time.Since(start)
diff --git a/scripts/03-system-registry.ps1 b/scripts/03-system-registry.ps1
index f62d5aa..93b7176 100644
--- a/scripts/03-system-registry.ps1
+++ b/scripts/03-system-registry.ps1
@@ -316,8 +316,11 @@ if (Get-Feature $Config "systemRegistry" "edgePolicies") {
Set-Reg -Path $edgePath -Name "HideFirstRunExperience" -Value 1
Set-Reg -Path $edgePath -Name "DefaultBrowserSettingEnabled" -Value 0
- # New tab page / recommendations
- Set-Reg -Path $edgePath -Name "NewTabPageContentEnabled" -Value 0
+ # New tab page - disable all visual clutter
+ Set-Reg -Path $edgePath -Name "NewTabPageContentEnabled" -Value 0 # feed / obsah
+ Set-Reg -Path $edgePath -Name "NewTabPageQuickLinksEnabled" -Value 0 # rychle odkazy
+ Set-Reg -Path $edgePath -Name "NewTabPageBackgroundEnabled" -Value 0 # pozadi
+ Set-Reg -Path $edgePath -Name "NewTabPageAllowedBackgroundTypes" -Value 3 # 3 = only solid color
Set-Reg -Path $edgePath -Name "ShowRecommendationsEnabled" -Value 0
Set-Reg -Path $edgePath -Name "SpotlightExperiencesAndRecommendationsEnabled" -Value 0
Set-Reg -Path $edgePath -Name "PersonalizationReportingEnabled" -Value 0
diff --git a/scripts/04-default-profile.ps1 b/scripts/04-default-profile.ps1
index 40d8eee..b963bb9 100644
--- a/scripts/04-default-profile.ps1
+++ b/scripts/04-default-profile.ps1
@@ -242,7 +242,12 @@ try {
'@
}
- default { "" } # empty = clean slate
+ default {
+@'
+
+
+'@
+ } # explicit pins with Replace = no Store, no other defaults
}
$taskbarLayoutXml = @"
diff --git a/scripts/05-personalization.ps1 b/scripts/05-personalization.ps1
index 16b79c8..987f5d0 100644
--- a/scripts/05-personalization.ps1
+++ b/scripts/05-personalization.ps1
@@ -101,6 +101,12 @@ function Apply-ThemeSettings {
Set-Reg -Path "$HiveRoot\Control Panel\Colors" `
-Name "Background" -Value "34 59 71" -Type "String"
+ # Empty Wallpaper path = solid color from Background key above.
+ # Without this, new users created from Default hive inherit a broken/missing
+ # wallpaper path and Windows falls back to black desktop.
+ Set-Reg -Path "$HiveRoot\Control Panel\Desktop" `
+ -Name "Wallpaper" -Value "" -Type "String"
+
Set-Reg -Path "$HiveRoot\Control Panel\Desktop" `
-Name "WallpaperStyle" -Value "0" -Type "String"