fix: taskbar pins, Edge NTP, black bg, step progress strip
All checks were successful
release / build-and-release (push) Successful in 22s

- 04-default-profile: default profile now pins Explorer+Edge (was empty),
  preventing MS Store and other defaults from appearing in taskbar
- 03-system-registry: disable Edge new tab page quick links, background,
  content feed (NewTabPageQuickLinksEnabled/BackgroundEnabled/AllowedBackgroundTypes)
- 05-personalization: set Wallpaper="" in default hive so new user accounts
  get solid-color background instead of black fallback
- runner: add onStepStart callback, fires before each script launch
- gui: step progress strip in run phase — color-coded labels per step
  (pending gray · / running blue ► / ok green ✓ / error red ✗ / skipped gray –)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
X9 Dev 2026-04-16 15:28:38 +02:00
parent 3991e7a6d0
commit 0462881980
5 changed files with 97 additions and 13 deletions

View file

@ -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()

View file

@ -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)

View file

@ -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

View file

@ -242,7 +242,12 @@ try {
<taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
}
default { "" } # empty = clean slate
default {
@'
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
<taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
} # explicit pins with Replace = no Store, no other defaults
}
$taskbarLayoutXml = @"

View file

@ -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"