Merge remote-tracking branch 'origin/feat/container-details' into feat/l-for-details
# Conflicts: # internal/ui/app/app_test.go
This commit is contained in:
commit
75f62240fc
15 files changed
+559
-8
No files matched your search
@@ -29,6 +29,22 @@ type groupsMsg struct {
|
||||
err error
|
||||
}
|
||||
|
||||
// A vault's, scope's or file's details beyond its listing load once a
|
||||
// session, when the cursor rests on it, and again with refresh. They're
|
||||
// extra: moving on cancels the load, and search never waits for them.
|
||||
type detailsState struct {
|
||||
attrs []provider.Attr
|
||||
err error
|
||||
loading bool
|
||||
}
|
||||
|
||||
type detailsMsg struct {
|
||||
req int
|
||||
key string
|
||||
attrs []provider.Attr
|
||||
err error
|
||||
}
|
||||
|
||||
// detailOf is the pane the fourth pane describes: the one in focus, or,
|
||||
// with the fourth in focus, the one it was entered from.
|
||||
func (m Model) detailOf() pane {
|
||||
@@ -70,7 +86,9 @@ func (m *Model) syncFields() tea.Cmd {
|
||||
m.fields.Show("lazysecrets", m.statusFields())
|
||||
case paneContainers:
|
||||
if c, ok := m.containers.Selected(); ok {
|
||||
cmd := m.loadDetails(c)
|
||||
m.fields.Show(c.Name, m.containerFields(c))
|
||||
return cmd
|
||||
} else {
|
||||
m.fields.Show("", nil)
|
||||
}
|
||||
@@ -177,9 +195,48 @@ func (m Model) containerFields(c provider.Container) []panes.Field {
|
||||
add(strings.ToLower(string(t))+"s", fmt.Sprint(len(e.value)))
|
||||
}
|
||||
}
|
||||
for _, a := range c.Attrs {
|
||||
out = append(out, panes.Field{Label: a.Label, Value: a.Value, Err: a.Warn})
|
||||
}
|
||||
switch st := m.details[containerKey(c)]; {
|
||||
case st.loading:
|
||||
out = append(out, panes.Field{Label: "details", Value: "loading…", Info: true})
|
||||
case errors.Is(st.err, provider.ErrUnsupported):
|
||||
case st.err != nil:
|
||||
out = append(out, panes.Field{Label: "details", Value: "couldn't load them: " + st.err.Error(), Info: true, Err: true})
|
||||
}
|
||||
for _, a := range m.details[containerKey(c)].attrs {
|
||||
out = append(out, panes.Field{Label: a.Label, Value: a.Value, Err: a.Warn})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// loadDetails loads c's details, if its provider has them and they
|
||||
// aren't loaded yet.
|
||||
func (m *Model) loadDetails(c provider.Container) tea.Cmd {
|
||||
d, ok := m.providerFor(c.Source).(provider.ContainerDetails)
|
||||
key := containerKey(c)
|
||||
if _, seen := m.details[key]; !ok || seen {
|
||||
return nil
|
||||
}
|
||||
// One at a time: the previous one, if it's still loading, is
|
||||
// cancelled and forgotten, to load when it's shown again.
|
||||
for k, st := range m.details {
|
||||
if st.loading {
|
||||
delete(m.details, k)
|
||||
}
|
||||
}
|
||||
m.details[key] = detailsState{loading: true}
|
||||
ctx, req := m.begin(slotDetails)
|
||||
return m.settled(ctx, func() tea.Msg {
|
||||
attrs, err := d.Details(ctx, c)
|
||||
if ctx.Err() != nil {
|
||||
err = ctx.Err()
|
||||
}
|
||||
return detailsMsg{req: req, key: key, attrs: attrs, err: err}
|
||||
})
|
||||
}
|
||||
|
||||
// problemFields show why an account has nothing to show, wrapped to the
|
||||
// pane, in red.
|
||||
func (m Model) problemFields(problem string) []panes.Field {
|
||||
|
||||
Reference in new issue
Block a user