diff --git a/main_test.go b/main_test.go index 7b86ebb..761ab07 100644 --- a/main_test.go +++ b/main_test.go @@ -5342,6 +5342,76 @@ func TestUIRemoteOpenButtonLabelUsesLocalCacheLanguageForBoundRemote(t *testing. } } +func TestUISelectedRemoteCardUsesLocalCacheSummaryForBoundRemote(t *testing.T) { + t.Parallel() + + u := newUIWithSession("desktop", &session.Manager{}) + u.lifecycleMode = "remote" + u.applyRecentRemoteRecord(recentRemoteRecord{ + BaseURL: "https://dav.example.invalid", + Path: "vaults/home.kdbx", + LocalVaultPath: "/vaults/cache/home.kdbx", + RemoteProfileID: "remote-profile-1", + CredentialEntryID: "remote-creds-1", + }) + u.recentRemotes = []recentRemoteRecord{{ + BaseURL: "https://dav.example.invalid", + Path: "vaults/home.kdbx", + LocalVaultPath: "/vaults/cache/home.kdbx", + RemoteProfileID: "remote-profile-1", + CredentialEntryID: "remote-creds-1", + LastGroup: []string{"Root", "Internet"}, + }} + + if got := u.selectedRemoteCardHeading(); got != "CACHED VAULT" { + t.Fatalf("selectedRemoteCardHeading() = %q, want %q", got, "CACHED VAULT") + } + if got := u.selectedRemoteCardPrimaryText(); got != "home.kdbx" { + t.Fatalf("selectedRemoteCardPrimaryText() = %q, want %q", got, "home.kdbx") + } + gotDetails := u.selectedRemoteCardDetailLines() + wantDetails := []string{ + "/vaults/cache", + "Sync target: home.kdbx · dav.example.invalid", + "Last group: Root / Internet", + } + if !slices.Equal(gotDetails, wantDetails) { + t.Fatalf("selectedRemoteCardDetailLines() = %v, want %v", gotDetails, wantDetails) + } +} + +func TestUISelectedRemoteCardUsesConnectionSummaryWithoutLocalCache(t *testing.T) { + t.Parallel() + + u := newUIWithSession("desktop", &session.Manager{}) + u.lifecycleMode = "remote" + u.applyRecentRemoteRecord(recentRemoteRecord{ + BaseURL: "https://dav.example.invalid", + Path: "vaults/home.kdbx", + }) + u.recentRemotes = []recentRemoteRecord{{ + BaseURL: "https://dav.example.invalid", + Path: "vaults/home.kdbx", + LastGroup: []string{"Root", "Internet"}, + }} + + if got := u.selectedRemoteCardHeading(); got != "SELECTED CONNECTION" { + t.Fatalf("selectedRemoteCardHeading() = %q, want %q", got, "SELECTED CONNECTION") + } + if got := u.selectedRemoteCardPrimaryText(); got != "home.kdbx · dav.example.invalid" { + t.Fatalf("selectedRemoteCardPrimaryText() = %q, want %q", got, "home.kdbx · dav.example.invalid") + } + gotDetails := u.selectedRemoteCardDetailLines() + wantDetails := []string{ + "Path: vaults/home.kdbx", + "Server: https://dav.example.invalid", + "Last group: Root / Internet", + } + if !slices.Equal(gotDetails, wantDetails) { + t.Fatalf("selectedRemoteCardDetailLines() = %v, want %v", gotDetails, wantDetails) + } +} + func TestUIOpenRemoteVaultRestoresLastOpenedGroupForThatConnection(t *testing.T) { t.Parallel() diff --git a/ui_forms.go b/ui_forms.go index 5aae825..28a814e 100644 --- a/ui_forms.go +++ b/ui_forms.go @@ -353,50 +353,81 @@ func (u *ui) lifecycleControls(gtx layout.Context) layout.Dimensions { } func (u *ui) selectedRemoteConnectionCard(gtx layout.Context) layout.Dimensions { - record := u.currentRemoteRecord() - lastGroup := u.recentRemoteGroup(record.BaseURL, record.Path) + heading := u.selectedRemoteCardHeading() + primary := u.selectedRemoteCardPrimaryText() + details := u.selectedRemoteCardDetailLines() return compactCard(gtx, func(gtx layout.Context) layout.Dimensions { return layout.UniformInset(unit.Dp(10)).Layout(gtx, func(gtx layout.Context) layout.Dimensions { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + children := []layout.FlexChild{ layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(12), "SELECTED CONNECTION") + lbl := material.Label(u.theme, unit.Sp(12), heading) lbl.Color = mutedColor return lbl.Layout(gtx) }), layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(14), friendlyRecentRemoteLabel(record)) + lbl := material.Label(u.theme, unit.Sp(14), primary) lbl.Color = accentColor return lbl.Layout(gtx) }), - layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(11), "Path: "+strings.TrimSpace(record.Path)) + } + for _, line := range details { + line := line + children = append(children, layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout)) + children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions { + lbl := material.Label(u.theme, unit.Sp(11), line) lbl.Color = mutedColor return lbl.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(11), "Server: "+strings.TrimSpace(record.BaseURL)) - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if len(lastGroup) == 0 { - return layout.Dimensions{} - } - lbl := material.Label(u.theme, unit.Sp(11), "Last group: "+strings.Join(u.displayEntryPath(lastGroup), " / ")) - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), + })) + } + children = append(children, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.clearRemoteSelection, "Open Different Connection") }), ) + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, children...) }) }) } +func (u *ui) selectedRemoteCardHeading() string { + if u.selectedRemoteUsesLocalCache() { + return "CACHED VAULT" + } + return "SELECTED CONNECTION" +} + +func (u *ui) selectedRemoteCardPrimaryText() string { + record := u.currentRemoteRecord() + if u.selectedRemoteUsesLocalCache() { + path := strings.TrimSpace(u.vaultPath.Text()) + if label := friendlyRecentVaultLabel(path); label != "" { + return label + } + } + return friendlyRecentRemoteLabel(record) +} + +func (u *ui) selectedRemoteCardDetailLines() []string { + record := u.currentRemoteRecord() + lastGroup := u.recentRemoteGroup(record.BaseURL, record.Path) + lines := make([]string, 0, 3) + if u.selectedRemoteUsesLocalCache() { + if dir := compactPathDirectorySummary(strings.TrimSpace(u.vaultPath.Text())); dir != "" { + lines = append(lines, dir) + } + lines = append(lines, "Sync target: "+friendlyRecentRemoteLabel(record)) + } else { + lines = append(lines, "Path: "+strings.TrimSpace(record.Path)) + lines = append(lines, "Server: "+strings.TrimSpace(record.BaseURL)) + } + if len(lastGroup) > 0 { + lines = append(lines, "Last group: "+strings.Join(u.displayEntryPath(lastGroup), " / ")) + } + return lines +} + func (u *ui) selectedLocalVaultCard(gtx layout.Context, path string) layout.Dimensions { lastGroup := u.recentVaultGroup(path) return compactCard(gtx, func(gtx layout.Context) layout.Dimensions {