refactor: no group list in an account's details, and no Microsoft Graph call for it
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
4b2a6a8ae8
commit
18918db1d4
8 files changed
+26
-232
No files matched your search
@@ -172,12 +172,10 @@ type Model struct {
|
||||
clip Clipboard
|
||||
clipClear time.Duration
|
||||
openURL func(string) error
|
||||
// fields is the fourth pane for anything but a secret, with each
|
||||
// account's groups as they load; lastLeft is the left pane it
|
||||
// describes while the fourth has focus (fields.go).
|
||||
// fields is the fourth pane for anything but a secret; lastLeft is
|
||||
// the left pane it describes while the fourth has focus (fields.go).
|
||||
fields panes.Fields
|
||||
lastLeft pane
|
||||
groups map[string]groupsState
|
||||
details map[string]detailsState // by containerKey
|
||||
getenv func(string) string
|
||||
nvimOpen func(server, path string, line int) error // edit.go
|
||||
@@ -377,7 +375,6 @@ func New(providers []provider.Provider, opts Options) Model {
|
||||
getenv: os.Getenv,
|
||||
nvimOpen: nvimOpen,
|
||||
cache: newCache(),
|
||||
groups: map[string]groupsState{},
|
||||
details: map[string]detailsState{},
|
||||
fields: panes.NewFields(),
|
||||
}
|
||||
@@ -590,9 +587,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case persistedMsg:
|
||||
m.handlePersisted(msg)
|
||||
|
||||
case groupsMsg:
|
||||
m.groups[msg.provider] = groupsState{names: msg.names, err: msg.err}
|
||||
|
||||
case detailsMsg:
|
||||
if msg.req == m.reqID[slotDetails] {
|
||||
m.done(slotDetails)
|
||||
|
||||
@@ -1106,25 +1106,16 @@ func TestAccountInDetails(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// grouped is an account in two groups.
|
||||
type grouped struct{ described }
|
||||
|
||||
func (grouped) Groups(context.Context) ([]string, error) {
|
||||
return []string{"Platform team", "Vault readers"}, nil
|
||||
}
|
||||
|
||||
func TestAccountPane(t *testing.T) {
|
||||
t.Parallel()
|
||||
d := newDriver(t, grouped{described{fake.Azure(0)}})
|
||||
d.keys("g", "tab") // the account's row, then straight to its pane
|
||||
d := newDriver(t, described{fake.Azure(0)})
|
||||
d.keys("g", "l") // the account's row, then its pane
|
||||
if d.m.focus != paneDetail {
|
||||
t.Fatalf("focus %v, want the fourth pane", d.m.focus)
|
||||
}
|
||||
scr := d.screen()
|
||||
for _, want := range []string{"Alice Example", "groups 2", "Platform team", "Vault readers"} {
|
||||
if !strings.Contains(scr, want) {
|
||||
t.Errorf("missing %q:\n%s", want, scr)
|
||||
}
|
||||
if !strings.Contains(scr, "Alice Example") {
|
||||
t.Errorf("account not shown:\n%s", scr)
|
||||
}
|
||||
bar := lastLine(scr)
|
||||
if !strings.Contains(bar, "copy") || strings.Contains(bar, "reveal") || strings.Contains(bar, "versions") {
|
||||
@@ -1134,28 +1125,20 @@ func TestAccountPane(t *testing.T) {
|
||||
if got := d.clip().content; got != "oid-123" {
|
||||
t.Errorf("y on the object ID copied %q", got)
|
||||
}
|
||||
d.keys("G", "y")
|
||||
if got := d.clip().content; got != "Vault readers" {
|
||||
t.Errorf("y on a group copied %q", got)
|
||||
}
|
||||
|
||||
// / filters it, labels too.
|
||||
d.keys("/")
|
||||
d.typeText("vault")
|
||||
d.typeText("object")
|
||||
d.keys("enter")
|
||||
if scr := d.screen(); !strings.Contains(scr, "Vault readers") || strings.Contains(scr, "Platform team") {
|
||||
if scr := d.screen(); !strings.Contains(scr, "oid-123") || strings.Contains(scr, "Alice Example") {
|
||||
t.Errorf("filtered:\n%s", scr)
|
||||
}
|
||||
d.keys("y")
|
||||
if got := d.clip().content; got != "Vault readers" {
|
||||
t.Errorf("y in the filtered pane copied %q", got)
|
||||
}
|
||||
d.keys("esc")
|
||||
if !strings.Contains(d.screen(), "Platform team") {
|
||||
if !strings.Contains(d.screen(), "Alice Example") {
|
||||
t.Errorf("filter not cleared:\n%s", d.screen())
|
||||
}
|
||||
|
||||
d.keys("shift+tab")
|
||||
d.keys("h")
|
||||
if d.m.focus != paneSources {
|
||||
t.Errorf("back to %v, want Sources", d.m.focus)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -14,20 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// The fourth pane shows Fields for anything but a secret. On a provider's
|
||||
// row: its account, from what the provider knows locally, then the
|
||||
// groups the account is in, loaded once a session when first shown.
|
||||
|
||||
type groupsState struct {
|
||||
names []string
|
||||
err error
|
||||
loading bool
|
||||
}
|
||||
|
||||
type groupsMsg struct {
|
||||
provider string
|
||||
names []string
|
||||
err error
|
||||
}
|
||||
// row: its account, from what the provider knows locally.
|
||||
|
||||
// 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
|
||||
@@ -57,7 +43,6 @@ func (m Model) detailOf() pane {
|
||||
// syncFields shows the Fields pane for what the focused pane has selected,
|
||||
// unless that's a secret (or a vault with the Secrets pane in focus), which
|
||||
// the secret pane shows, as it does a revealed value whatever the focus.
|
||||
// An account's groups load the first time.
|
||||
func (m *Model) syncFields() tea.Cmd {
|
||||
if m.detail.State() != panes.ValueHidden {
|
||||
// A value revealed (or being fetched) from any pane stays in
|
||||
@@ -76,7 +61,7 @@ func (m *Model) syncFields() tea.Cmd {
|
||||
case m.selectedProblem() != "":
|
||||
m.fields.Show(cmpOr(r.label, r.source.Name), m.problemFields(m.selectedProblem()))
|
||||
case r.kind == rowGroup:
|
||||
return m.showAccount(r)
|
||||
m.showAccount(r)
|
||||
case r.kind == rowSource:
|
||||
m.fields.Show(r.source.Name, m.sourceFields(r.source))
|
||||
default:
|
||||
@@ -98,9 +83,8 @@ func (m *Model) syncFields() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
// showAccount shows a provider's account, loading its groups the first
|
||||
// time.
|
||||
func (m *Model) showAccount(r sourceRow) tea.Cmd {
|
||||
// showAccount shows a provider's account.
|
||||
func (m *Model) showAccount(r sourceRow) {
|
||||
p := m.byID[r.provider]
|
||||
var fields []panes.Field
|
||||
if a, ok := p.(provider.Accounts); ok {
|
||||
@@ -110,28 +94,11 @@ func (m *Model) showAccount(r sourceRow) tea.Cmd {
|
||||
}
|
||||
}
|
||||
}
|
||||
var cmd tea.Cmd
|
||||
if g, ok := p.(provider.AccountGroups); ok {
|
||||
st, seen := m.groups[r.provider]
|
||||
if !seen {
|
||||
st = groupsState{loading: true}
|
||||
m.groups[r.provider] = st
|
||||
id, timeout := r.provider, m.timeout
|
||||
cmd = func() tea.Msg {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
names, err := g.Groups(ctx)
|
||||
return groupsMsg{provider: id, names: names, err: err}
|
||||
}
|
||||
}
|
||||
fields = append(fields, groupFields(st)...)
|
||||
}
|
||||
if res, done := m.sourceResults[r.provider]; done && res.err == nil && len(res.sources) == 0 {
|
||||
hint := emptyHint(p.Kind())
|
||||
fields = append(fields, panes.Field{Label: "nothing", Value: "found: try", Info: true}, panes.Field{Value: hint.Value, URL: hint.URL})
|
||||
}
|
||||
m.fields.Show(p.Label(), fields)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// sourceFields describe a subscription, workspace or repo.
|
||||
@@ -248,30 +215,8 @@ func (m Model) problemFields(problem string) []panes.Field {
|
||||
return out
|
||||
}
|
||||
|
||||
// fieldName names a copied field: its label, or for a group, the group.
|
||||
// fieldName names a copied field: its label, or a row of several under
|
||||
// one label (a tag), its value.
|
||||
func fieldName(f panes.Field) string {
|
||||
if f.Label == "" || strings.HasPrefix(f.Label, "groups") {
|
||||
return "group " + f.Value
|
||||
}
|
||||
return f.Label
|
||||
}
|
||||
|
||||
// groupFields are the groups' rows: labelled on the first.
|
||||
func groupFields(st groupsState) []panes.Field {
|
||||
switch {
|
||||
case st.loading:
|
||||
return []panes.Field{{Label: "groups", Value: "loading…", Info: true}}
|
||||
case errors.Is(st.err, provider.ErrUnsupported):
|
||||
return nil
|
||||
case st.err != nil:
|
||||
return []panes.Field{{Label: "groups", Value: "couldn't list them: " + st.err.Error(), Info: true}}
|
||||
case len(st.names) == 0:
|
||||
return []panes.Field{{Label: "groups", Value: "none", Info: true}}
|
||||
}
|
||||
out := make([]panes.Field, len(st.names))
|
||||
for i, n := range st.names {
|
||||
out[i] = panes.Field{Value: n}
|
||||
}
|
||||
out[0].Label = fmt.Sprintf("groups %d", len(st.names))
|
||||
return out
|
||||
return cmpOr(f.Label, f.Value)
|
||||
}
|
||||
Reference in new issue
Block a user