Remember recent remote vault connections
This commit is contained in:
@@ -78,6 +78,7 @@ type attachmentItem struct {
|
||||
type statePaths struct {
|
||||
DefaultSaveAsPath string
|
||||
RecentVaultsPath string
|
||||
RecentRemotesPath string
|
||||
}
|
||||
|
||||
type recentVaultRecord struct {
|
||||
@@ -85,6 +86,13 @@ type recentVaultRecord struct {
|
||||
LastGroup []string `json:"lastGroup,omitempty"`
|
||||
}
|
||||
|
||||
type recentRemoteRecord struct {
|
||||
BaseURL string `json:"baseUrl"`
|
||||
Path string `json:"path"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
type ui struct {
|
||||
mode string
|
||||
theme *material.Theme
|
||||
@@ -159,12 +167,14 @@ type ui struct {
|
||||
showRecycle widget.Clickable
|
||||
showLocalLifecycle widget.Clickable
|
||||
showRemoteLifecycle widget.Clickable
|
||||
rememberRemoteAuth widget.Bool
|
||||
entryClicks []widget.Clickable
|
||||
historyClicks []widget.Clickable
|
||||
attachmentClicks []widget.Clickable
|
||||
breadcrumbs []widget.Clickable
|
||||
groupClicks []widget.Clickable
|
||||
recentVaultClicks []widget.Clickable
|
||||
recentRemoteClicks []widget.Clickable
|
||||
removeCustomFields []widget.Clickable
|
||||
state appstate.State
|
||||
visible []entry
|
||||
@@ -189,9 +199,11 @@ type ui struct {
|
||||
keyboardFocus focusID
|
||||
defaultSaveAsPath string
|
||||
recentVaultsPath string
|
||||
recentRemotesPath string
|
||||
editingEntry bool
|
||||
groupControlsHidden bool
|
||||
recentVaults []string
|
||||
recentRemotes []recentRemoteRecord
|
||||
recentVaultGroups map[string][]string
|
||||
deleteGroupPath []string
|
||||
statusExpiresAt time.Time
|
||||
@@ -276,6 +288,7 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
|
||||
lifecycleMode: "local",
|
||||
defaultSaveAsPath: paths.DefaultSaveAsPath,
|
||||
recentVaultsPath: paths.RecentVaultsPath,
|
||||
recentRemotesPath: paths.RecentRemotesPath,
|
||||
recentVaultGroups: map[string][]string{},
|
||||
now: time.Now,
|
||||
}
|
||||
@@ -290,6 +303,7 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
|
||||
u.keyboardFocus = focusSearch
|
||||
u.setCustomFieldRows(nil)
|
||||
u.loadRecentVaults()
|
||||
u.loadRecentRemotes()
|
||||
u.filter()
|
||||
return u
|
||||
}
|
||||
@@ -322,6 +336,7 @@ func defaultStatePaths(stateDir string) statePaths {
|
||||
return statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(baseDir, "vault.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(baseDir, "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(baseDir, "recent-remotes.json"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +566,13 @@ func (u *ui) openRemoteAction() error {
|
||||
if err := u.state.OpenRemoteVault(client, strings.TrimSpace(u.remotePath.Text()), key); err != nil {
|
||||
return err
|
||||
}
|
||||
u.noteRecentRemote(
|
||||
strings.TrimSpace(u.remoteBaseURL.Text()),
|
||||
strings.TrimSpace(u.remotePath.Text()),
|
||||
strings.TrimSpace(u.remoteUsername.Text()),
|
||||
u.remotePassword.Text(),
|
||||
u.rememberRemoteAuth.Value,
|
||||
)
|
||||
u.enterHiddenVaultRoot()
|
||||
u.editingEntry = false
|
||||
u.filter()
|
||||
@@ -695,6 +717,42 @@ func (u *ui) applyRecentVaultRecords(records []recentVaultRecord) {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ui) loadRecentRemotes() {
|
||||
if strings.TrimSpace(u.recentRemotesPath) == "" {
|
||||
return
|
||||
}
|
||||
content, err := os.ReadFile(u.recentRemotesPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var records []recentRemoteRecord
|
||||
if err := json.Unmarshal(content, &records); err != nil {
|
||||
return
|
||||
}
|
||||
filtered := make([]recentRemoteRecord, 0, len(records))
|
||||
seen := map[string]bool{}
|
||||
for _, record := range records {
|
||||
record.BaseURL = strings.TrimSpace(record.BaseURL)
|
||||
record.Path = strings.TrimSpace(record.Path)
|
||||
if record.BaseURL == "" || record.Path == "" {
|
||||
continue
|
||||
}
|
||||
key := record.BaseURL + "|" + record.Path
|
||||
if seen[key] {
|
||||
continue
|
||||
}
|
||||
seen[key] = true
|
||||
filtered = append(filtered, record)
|
||||
if len(filtered) == 6 {
|
||||
break
|
||||
}
|
||||
}
|
||||
u.recentRemotes = filtered
|
||||
if len(u.recentRemoteClicks) < len(u.recentRemotes) {
|
||||
u.recentRemoteClicks = make([]widget.Clickable, len(u.recentRemotes))
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ui) saveRecentVaults() {
|
||||
if strings.TrimSpace(u.recentVaultsPath) == "" {
|
||||
return
|
||||
@@ -716,6 +774,51 @@ func (u *ui) saveRecentVaults() {
|
||||
_ = os.WriteFile(u.recentVaultsPath, content, 0o600)
|
||||
}
|
||||
|
||||
func (u *ui) saveRecentRemotes() {
|
||||
if strings.TrimSpace(u.recentRemotesPath) == "" {
|
||||
return
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(u.recentRemotesPath), 0o700); err != nil {
|
||||
return
|
||||
}
|
||||
content, err := json.MarshalIndent(u.recentRemotes, "", " ")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = os.WriteFile(u.recentRemotesPath, content, 0o600)
|
||||
}
|
||||
|
||||
func (u *ui) noteRecentRemote(baseURL, path, username, password string, rememberAuth bool) {
|
||||
baseURL = strings.TrimSpace(baseURL)
|
||||
path = strings.TrimSpace(path)
|
||||
if baseURL == "" || path == "" {
|
||||
return
|
||||
}
|
||||
record := recentRemoteRecord{
|
||||
BaseURL: baseURL,
|
||||
Path: path,
|
||||
}
|
||||
if rememberAuth {
|
||||
record.Username = strings.TrimSpace(username)
|
||||
record.Password = password
|
||||
}
|
||||
next := []recentRemoteRecord{record}
|
||||
for _, existing := range u.recentRemotes {
|
||||
if existing.BaseURL == baseURL && existing.Path == path {
|
||||
continue
|
||||
}
|
||||
next = append(next, existing)
|
||||
if len(next) == 6 {
|
||||
break
|
||||
}
|
||||
}
|
||||
u.recentRemotes = next
|
||||
if len(u.recentRemoteClicks) < len(u.recentRemotes) {
|
||||
u.recentRemoteClicks = make([]widget.Clickable, len(u.recentRemotes))
|
||||
}
|
||||
u.saveRecentRemotes()
|
||||
}
|
||||
|
||||
func (u *ui) recentVaultGroup(path string) []string {
|
||||
if u.recentVaultGroups == nil {
|
||||
return nil
|
||||
@@ -1128,6 +1231,18 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range u.recentRemoteClicks {
|
||||
for u.recentRemoteClicks[i].Clicked(gtx) {
|
||||
if i < len(u.recentRemotes) {
|
||||
record := u.recentRemotes[i]
|
||||
u.remoteBaseURL.SetText(record.BaseURL)
|
||||
u.remotePath.SetText(record.Path)
|
||||
u.remoteUsername.SetText(record.Username)
|
||||
u.remotePassword.SetText(record.Password)
|
||||
u.rememberRemoteAuth.Value = strings.TrimSpace(record.Username) != "" || record.Password != ""
|
||||
}
|
||||
}
|
||||
}
|
||||
for u.addEntry.Clicked(gtx) {
|
||||
u.state.BeginNewEntry()
|
||||
u.loadSelectedEntryIntoEditor()
|
||||
|
||||
Reference in New Issue
Block a user