1package modes
2
3import (
4 "context"
5 "fmt"
6 "strings"
7 "time"
8
9 "github.com/patriceckhart/zot/packages/agent/extensions"
10 "github.com/patriceckhart/zot/packages/tui"
11)
12
13const reloadStatusDuration = 5 * time.Second
14
15func formatReloadStatus(stats extensions.ReloadStats) (string, bool) {
16 msg := fmt.Sprintf("reloaded: %d stopped, %d loaded (%d ready)", stats.Stopped, stats.Loaded, stats.Ready)
17 if len(stats.Errors) == 0 {
18 return msg, false
19 }
20 details := make([]string, 0, len(stats.Errors))
21 for _, err := range stats.Errors {
22 if err != nil {
23 details = append(details, err.Error())
24 }
25 }
26 msg += fmt.Sprintf(", %d error(s)", len(stats.Errors))
27 if len(details) > 0 {
28 msg += ": " + strings.Join(details, "; ")
29 }
30 return msg, true
31}
32
33func (i *Interactive) setReloadStatus(msg string, failed bool) uint64 {
34 i.mu.Lock()
35 defer i.mu.Unlock()
36 i.reloadStatusSeq++
37 if failed {
38 i.statusOK = ""
39 i.statusErr = msg
40 i.reloadErrors = append(i.reloadErrors, msg)
41 return i.reloadStatusSeq
42 }
43 i.statusOK = msg
44 i.statusErr = ""
45 return i.reloadStatusSeq
46}
47
48func renderReloadErrors(theme tui.Theme, errors []string, width int) []string {
49 const marker = "✖ "
50 const indent = " "
51 wrapWidth := width - len([]rune(marker))
52 if wrapWidth < 8 {
53 wrapWidth = 8
54 }
55 var out []string
56 for _, msg := range errors {
57 wrapped := tui.WrapANSILine(msg, wrapWidth)
58 if len(wrapped) == 0 {
59 wrapped = []string{""}
60 }
61 for idx, line := range wrapped {
62 prefix := marker
63 if idx > 0 {
64 prefix = indent
65 }
66 out = append(out, theme.FG256(theme.Error, prefix+line))
67 }
68 }
69 return out
70}
71
72func (i *Interactive) clearReloadStatus(seq uint64, msg string, failed bool) bool {
73 i.mu.Lock()
74 defer i.mu.Unlock()
75 if i.reloadStatusSeq != seq {
76 return false
77 }
78 if failed {
79 if i.statusErr != msg {
80 return false
81 }
82 i.statusErr = ""
83 return true
84 }
85 if i.statusOK != msg {
86 return false
87 }
88 i.statusOK = ""
89 return true
90}
91
92func (i *Interactive) dismissReloadStatus(ctx context.Context, seq uint64, msg string, failed bool) {
93 timer := time.NewTimer(reloadStatusDuration)
94 defer timer.Stop()
95 select {
96 case <-ctx.Done():
97 return
98 case <-timer.C:
99 if i.clearReloadStatus(seq, msg, failed) {
100 i.invalidate()
101 }
102 }
103}