feat: opening a link to a secret ends on its details
CI / Checks (pull_request) Successful in 35s
PR title / Conventional title (pull_request) Successful in 1s

As enter on it would, instead of on the vault's list with the secret
selected: ctrl+o, a paste, a clicked link and the share failure
popup's g. Going back to where lazysecrets was left, and Go to, stay
as they were.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kebandClaude Opus 5.5 committed 2026-10-13 14:06:16 +02:00
1 parent 2a3379b1c1
commit 7d6a095e42
4 files changed
+25 -10

No files matched your search

+3 -3
View File
@@ -118,9 +118,9 @@ read the clipboard over SSH.
lazysecrets finds the vault in your accounts (one Resource Graph query per
account) and jumps to it, asking which account to use when several can see
it. Links say what, not what to do: opening a link to a secret asks whether
to just go to it, also copy or show its value, or (`y`) copy its value
without going there.
it, ending on a secret's details as `enter` on it would. Links say what,
not what to do: opening a link to a secret asks whether to just go to it,
also copy or show its value, or (`y`) copy its value without going there.
## In scripts
+1 -1
View File
@@ -217,7 +217,7 @@ func (m *Model) jumpTo(r ref.Ref, n store.Node) tea.Cmd {
case 1:
m.startNav(r, actGo, choices[0].sourceRow)
default:
m.chooseSource("Several accounts can see "+r.ContainerName(), r, actGo, choices)
m.chooseSource("Several accounts can see "+r.ContainerName(), r, actGo, choices, false)
}
return nil
}
+19 -5
View File
@@ -46,6 +46,9 @@ type nav struct {
// quiet gives up without a word: going back to where lazysecrets
// was left, which may be gone.
quiet bool
// link ends on the object's details, as enter on it would: opening
// a link to it opens it, rather than just finding it in its list.
link bool
}
type resolvedMsg struct {
@@ -401,23 +404,30 @@ func (m *Model) handleResolved(msg resolvedMsg) {
for i := range msg.choices {
msg.choices[i].label = "Open in " + msg.choices[i].label
}
m.chooseSource("Scope "+msg.ref.Scope+" is in several workspaces", msg.ref, msg.act, msg.choices)
m.chooseSource("Scope "+msg.ref.Scope+" is in several workspaces", msg.ref, msg.act, msg.choices, true)
case len(msg.others) > 0:
var choices []choice
for _, row := range append([]string{msg.sourceRow}, msg.others...) {
choices = append(choices, choice{label: "Open with " + m.sourceLabel(row), sourceRow: row})
}
m.chooseSource("Several accounts can see "+msg.ref.ContainerName(), msg.ref, msg.act, choices)
m.chooseSource("Several accounts can see "+msg.ref.ContainerName(), msg.ref, msg.act, choices, true)
case msg.linked != nil:
m.addLinked(*msg.linked)
m.startNav(msg.ref, msg.act, linksRowID)
m.startLinkNav(msg.ref, msg.act, linksRowID)
default:
m.startNav(msg.ref, msg.act, msg.sourceRow)
m.startLinkNav(msg.ref, msg.act, msg.sourceRow)
}
}
// startLinkNav opens a link: like startNav, ending on its object's
// details.
func (m *Model) startLinkNav(r ref.Ref, act linkAction, sourceRow string) {
m.startNav(r, act, sourceRow)
m.nav.link = true
}
// chooseSource asks where to open r.
func (m *Model) chooseSource(title string, r ref.Ref, act linkAction, choices []choice) {
func (m *Model) chooseSource(title string, r ref.Ref, act linkAction, choices []choice, link bool) {
var opts []option
for i, c := range choices {
key := ""
@@ -427,6 +437,7 @@ func (m *Model) chooseSource(title string, r ref.Ref, act linkAction, choices []
row := c.sourceRow
opts = append(opts, option{key: key, label: c.label, run: func(m *Model) tea.Cmd {
m.startNav(r, act, row)
m.nav.link = link
return nil
}})
}
@@ -577,6 +588,9 @@ func (m *Model) advanceNav() bool {
m.pendingCmd = m.toggleReveal()
}
}
if n.link {
m.focus = paneDetail // after: copying acts on the focused pane
}
return true
}
return false
+2 -1
View File
@@ -40,7 +40,8 @@ func TestOpenSecretLink(t *testing.T) {
if src, c, s := d.selected(); src != "platform-prod" || c != "kv-app-prod" || s != "api-key" {
t.Fatalf("opened %s/%s/%s", src, c, s)
}
if d.m.focus != paneSecrets || d.m.detail.State() != panes.ValueHidden {
// Opened: on its details, as enter on it would; its value hidden.
if d.m.focus != paneDetail || d.m.detail.State() != panes.ValueHidden {
t.Errorf("focus %d, value state %d", d.m.focus, d.m.detail.State())
}
}