feat: the value's keys on the line below it: reveal and copy (#8)

This commit was merged in pull request #8.
This commit is contained in:
keb committed 2026-10-11 10:38:00 +02:00
1 parent 71396f1e02
commit c8abc1dc95
4 files changed
+45 -34

No files matched your search

+1 -1
View File
@@ -395,7 +395,7 @@ func New(providers []provider.Provider, opts Options) Model {
if opts.Keys != nil {
m.keys = *opts.Keys
}
m.detail.RevealKey, m.detail.VersionsKey = keys.Name(m.keys.Reveal), keys.Name(m.keys.Versions)
m.detail.RevealKey, m.detail.VersionsKey, m.detail.CopyKey = keys.Name(m.keys.Reveal), keys.Name(m.keys.Versions), keys.Name(m.keys.Copy)
m.revealTimeout, m.hideOnBlur = opts.RevealTimeout, opts.HideOnBlur
m.expiryWarning = opts.ExpiryWarning
m.handlerSetup = opts.HandlerSetup
+2 -2
View File
@@ -204,7 +204,7 @@ func TestObjectTypeTabs(t *testing.T) {
t.Fatalf("selected = %q", s)
}
screen := d.screen()
for _, want := range []string{"key type RSA 2048", "ops sign, verify", "space to show public key"} {
for _, want := range []string{"key type RSA 2048", "ops sign, verify", "space to show the public key"} {
if !strings.Contains(screen, want) {
t.Errorf("missing %q:\n%s", want, screen)
}
@@ -979,7 +979,7 @@ func TestRebindingShowsEverywhere(t *testing.T) {
d := newDriverOpts(t, Options{Keys: &km})
d.keys("3")
scr := d.screen()
if !strings.Contains(scr, "(z to reveal)") || strings.Contains(scr, "space to reveal") {
if !strings.Contains(scr, "z to reveal") || strings.Contains(scr, "space to reveal") {
t.Errorf("detail hint doesn't follow the binding:\n%s", scr)
}
if !strings.Contains(lastLine(scr), "z reveal/hide") {
+7 -7
View File
@@ -11,13 +11,13 @@
│ kv-restricted ││ ref @Microsoft.KeyVault(SecretUri=https://kv-app-prod.vau│
│ ││ lt.azure.net/secrets/db-password) │
│ ││ │
│ ││ value •••••••• (space to reveal) │
│ ││ │
╰────────────────────── 1 of 3 ─╯│ versions 3 · v to browse │
╭─ [3] Secrets - Keys - Certs ──╮│ ▸ 3f9c2a 2026-09-01 current │
│ db-password ││ 91d3e0 2026-03-01 expired │
│ api-key ││ 0a77c4 2025-09-01 disabled │
│ legacy-token (disabled) ││ │
│ ││ value •••••••• │
│ ││ space to reveal · y to copy │
╰────────────────────── 1 of 3 ─╯│ │
╭─ [3] Secrets - Keys - Certs ──╮│ versions 3 · v to browse │
│ db-password ││ ▸ 3f9c2a 2026-09-01 current │
│ api-key ││ 91d3e0 2026-03-01 expired │
│ legacy-token (disabled) ││ 0a77c4 2025-09-01 disabled │
│ ││ │
│ ││ │
│ ││ │
+35 -24
View File
@@ -31,7 +31,7 @@ type Detail struct {
Icons icons.Set
// RevealKey and VersionsKey are the keys hints mention ("space to
// reveal"); a hint is left out when its key is "" (unbound).
RevealKey, VersionsKey string
RevealKey, VersionsKey, CopyKey string
secret *provider.Object
container *provider.Container
@@ -69,7 +69,7 @@ func (d *Detail) ShowContainer(c provider.Container) {
// Clear drops the selection and any fetched value.
func (d *Detail) Clear() {
*d = Detail{Now: d.Now, Icons: d.Icons, RevealKey: d.RevealKey, VersionsKey: d.VersionsKey, w: d.w, h: d.h} // drops the note too
*d = Detail{Now: d.Now, Icons: d.Icons, RevealKey: d.RevealKey, VersionsKey: d.VersionsKey, CopyKey: d.CopyKey, w: d.w, h: d.h} // drops the note too
}
// SetMessage sets what's shown instead of the hint when nothing is
@@ -273,24 +273,35 @@ func (d Detail) lines(st styles.Styles) []string {
}
// Secrets are masked; keys and certificates only expose public material.
keyHint := func(k, what string) string {
if k == "" {
return ""
// What the keys do with the value, on the line under it.
hints := func(reveal string, more ...string) string {
var h []string
if d.RevealKey != "" {
h = append(h, d.RevealKey+" to "+reveal)
}
return "(" + k + " to " + what + ")"
if d.CopyKey != "" {
h = append(h, d.CopyKey+" to copy")
}
return muted(strings.Join(append(h, more...), " · "))
}
label, hidden := "value", st.Masked.Render("••••••••")+muted(" "+keyHint(d.RevealKey, "reveal"))
label, hidden, reveal := "value", st.Masked.Render("••••••••"), "reveal"
switch s.Type {
case provider.TypeKey:
label, hidden = "public", muted(keyHint(d.RevealKey, "show public key"))
label, hidden, reveal = "public", "", "show the public key"
case provider.TypeCertificate:
label, hidden = "cert", muted(keyHint(d.RevealKey, "show certificate"))
label, hidden, reveal = "cert", "", "show the certificate"
}
indent := strings.Repeat(" ", 12)
out = append(out, "")
switch d.state {
case ValueHidden:
field(label, hidden)
if hidden != "" {
field(label, hidden)
out = append(out, indent+hints(reveal))
} else {
field(label, hints(reveal))
}
case ValueLoading:
field(label, spinnerPlaceholder+" fetching…")
case ValueFailed:
@@ -311,23 +322,23 @@ func (d Detail) lines(st styles.Styles) []string {
}
}
case ValueShown:
var hints []string
if d.RevealKey != "" {
hints = append(hints, d.RevealKey+" to hide")
}
if d.hidesIn != "" {
hints = append(hints, "hides in "+d.hidesIn)
}
line := " " + st.Label.Render(label)
if len(hints) > 0 {
line += muted(" (" + strings.Join(hints, " · ") + ")")
}
out = append(out, line)
// Where the dots were, continuing under itself; the keys below.
first := true
for _, line := range strings.Split(d.value.Reveal(), "\n") {
for _, w := range strings.Split(ansi.Hardwrap(line, inner, true), "\n") {
out = append(out, " "+st.Value.Render(w))
for _, w := range strings.Split(ansi.Hardwrap(line, max(1, inner-11), true), "\n") {
if first {
out = append(out, " "+st.Label.Render(fmt.Sprintf("%-10s", label))+" "+st.Value.Render(w))
first = false
} else {
out = append(out, indent+st.Value.Render(w))
}
}
}
var more []string
if d.hidesIn != "" {
more = append(more, "hides in "+d.hidesIn)
}
out = append(out, indent+hints("hide", more...))
}
return append(out, d.versionLines(st)...)
}