Add sync mode choice to remote setup
This commit is contained in:
@@ -380,6 +380,7 @@ type ui struct {
|
|||||||
cancelLifecycleProgress widget.Clickable
|
cancelLifecycleProgress widget.Clickable
|
||||||
retryLifecycleOpen widget.Clickable
|
retryLifecycleOpen widget.Clickable
|
||||||
approvalPermanent widget.Bool
|
approvalPermanent widget.Bool
|
||||||
|
syncSetupAutomatic widget.Bool
|
||||||
apiPolicyAllow widget.Bool
|
apiPolicyAllow widget.Bool
|
||||||
apiPolicyGroupScopeW widget.Bool
|
apiPolicyGroupScopeW widget.Bool
|
||||||
apiTokenDisabled widget.Bool
|
apiTokenDisabled widget.Bool
|
||||||
@@ -1387,11 +1388,15 @@ func (u *ui) openRemoteSyncSetupDialog() {
|
|||||||
u.syncDialogPurpose = syncDialogPurposeRemoteSetup
|
u.syncDialogPurpose = syncDialogPurposeRemoteSetup
|
||||||
u.syncSourceMode = syncSourceRemote
|
u.syncSourceMode = syncSourceRemote
|
||||||
u.syncDirection = syncDirectionPush
|
u.syncDirection = syncDirectionPush
|
||||||
|
u.syncSetupAutomatic.Value = true
|
||||||
if strings.TrimSpace(u.syncLocalPath.Text()) == "" {
|
if strings.TrimSpace(u.syncLocalPath.Text()) == "" {
|
||||||
u.syncLocalPath.SetText(strings.TrimSpace(u.vaultPath.Text()))
|
u.syncLocalPath.SetText(strings.TrimSpace(u.vaultPath.Text()))
|
||||||
}
|
}
|
||||||
u.syncSavedRemoteBindingSelection()
|
u.syncSavedRemoteBindingSelection()
|
||||||
u.prefillAdvancedSyncRemoteFromSavedBinding()
|
u.prefillAdvancedSyncRemoteFromSavedBinding()
|
||||||
|
if _, ok := u.selectedVaultRemoteBinding(); ok && u.selectedVaultRemoteSyncMode == appstate.SyncModeManual {
|
||||||
|
u.syncSetupAutomatic.Value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ui) clearSyncLocalImport() {
|
func (u *ui) clearSyncLocalImport() {
|
||||||
@@ -1576,7 +1581,7 @@ func (u *ui) persistSyncDialogRemoteBinding(baseURL, remotePath string) error {
|
|||||||
Username: strings.TrimSpace(u.syncRemoteUsername.Text()),
|
Username: strings.TrimSpace(u.syncRemoteUsername.Text()),
|
||||||
Password: u.syncRemotePassword.Text(),
|
Password: u.syncRemotePassword.Text(),
|
||||||
CredentialPath: append([]string(nil), u.currentPath...),
|
CredentialPath: append([]string(nil), u.currentPath...),
|
||||||
SyncMode: u.newRemoteBindingSyncMode(),
|
SyncMode: u.syncSetupMode(),
|
||||||
}
|
}
|
||||||
binding, err := u.state.ConfigureRemoteBinding(input)
|
binding, err := u.state.ConfigureRemoteBinding(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2380,6 +2385,13 @@ func (u *ui) shouldShowSyncSourceChoices() bool {
|
|||||||
return u.syncDialogPurpose != syncDialogPurposeRemoteSetup
|
return u.syncDialogPurpose != syncDialogPurposeRemoteSetup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *ui) syncSetupMode() appstate.SyncMode {
|
||||||
|
if u.syncSetupAutomatic.Value {
|
||||||
|
return appstate.SyncModeAutomaticOnOpenSave
|
||||||
|
}
|
||||||
|
return appstate.SyncModeManual
|
||||||
|
}
|
||||||
|
|
||||||
func (u *ui) selectVaultRemoteProfile(id string) {
|
func (u *ui) selectVaultRemoteProfile(id string) {
|
||||||
id = strings.TrimSpace(id)
|
id = strings.TrimSpace(id)
|
||||||
u.selectedVaultRemoteProfileID = id
|
u.selectedVaultRemoteProfileID = id
|
||||||
@@ -5079,6 +5091,16 @@ func (u *ui) syncDialogContent(gtx layout.Context) layout.Dimensions {
|
|||||||
return u.syncPasswordField(gtx)
|
return u.syncPasswordField(gtx)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
if u.syncDialogPurpose == syncDialogPurposeRemoteSetup {
|
||||||
|
children = append(children,
|
||||||
|
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
check := material.CheckBox(u.theme, &u.syncSetupAutomatic, "Sync automatically on open and save")
|
||||||
|
check.Color = accentColor
|
||||||
|
return check.Layout(gtx)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
if len(matchingCredentials) > 0 {
|
if len(matchingCredentials) > 0 {
|
||||||
children = append(children,
|
children = append(children,
|
||||||
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||||
|
|||||||
@@ -5942,6 +5942,7 @@ func TestUISyncDialogUsesRemoteSetupCopy(t *testing.T) {
|
|||||||
|
|
||||||
u := newUIWithSession("desktop", &session.Manager{})
|
u := newUIWithSession("desktop", &session.Manager{})
|
||||||
u.syncDialogPurpose = syncDialogPurposeRemoteSetup
|
u.syncDialogPurpose = syncDialogPurposeRemoteSetup
|
||||||
|
u.syncSetupAutomatic.Value = true
|
||||||
|
|
||||||
if got := u.syncDialogTitle(); got != "Set Up Remote Sync" {
|
if got := u.syncDialogTitle(); got != "Set Up Remote Sync" {
|
||||||
t.Fatalf("syncDialogTitle() = %q, want Set Up Remote Sync", got)
|
t.Fatalf("syncDialogTitle() = %q, want Set Up Remote Sync", got)
|
||||||
@@ -5961,6 +5962,9 @@ func TestUISyncDialogUsesRemoteSetupCopy(t *testing.T) {
|
|||||||
if got := syncDialogSummaryText(syncDialogPurposeRemoteSetup, syncSourceRemote, syncDirectionPush); got != "Push this local vault to a WebDAV target and save that target for future sync." {
|
if got := syncDialogSummaryText(syncDialogPurposeRemoteSetup, syncSourceRemote, syncDirectionPush); got != "Push this local vault to a WebDAV target and save that target for future sync." {
|
||||||
t.Fatalf("syncDialogSummaryText(remote setup) = %q, want setup-specific summary", got)
|
t.Fatalf("syncDialogSummaryText(remote setup) = %q, want setup-specific summary", got)
|
||||||
}
|
}
|
||||||
|
if got := u.syncSetupMode(); got != appstate.SyncModeAutomaticOnOpenSave {
|
||||||
|
t.Fatalf("syncSetupMode() = %q, want automatic_on_open_save", got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUISyncDialogUsesAdvancedCopy(t *testing.T) {
|
func TestUISyncDialogUsesAdvancedCopy(t *testing.T) {
|
||||||
@@ -6056,6 +6060,9 @@ func TestUIRemoteSyncSetupPersistsBindingAfterSuccessfulPush(t *testing.T) {
|
|||||||
if got := u.recentRemotes[0].LocalVaultPath; got != currentPath {
|
if got := u.recentRemotes[0].LocalVaultPath; got != currentPath {
|
||||||
t.Fatalf("recentRemotes[0].LocalVaultPath = %q, want %q", got, currentPath)
|
t.Fatalf("recentRemotes[0].LocalVaultPath = %q, want %q", got, currentPath)
|
||||||
}
|
}
|
||||||
|
if got := u.selectedVaultRemoteSyncMode; got != appstate.SyncModeAutomaticOnOpenSave {
|
||||||
|
t.Fatalf("selectedVaultRemoteSyncMode = %q, want automatic_on_open_save", got)
|
||||||
|
}
|
||||||
if got := u.state.StatusMessage; got != "Remote sync is set up for this vault." {
|
if got := u.state.StatusMessage; got != "Remote sync is set up for this vault." {
|
||||||
t.Fatalf("StatusMessage = %q, want setup success message", got)
|
t.Fatalf("StatusMessage = %q, want setup success message", got)
|
||||||
}
|
}
|
||||||
@@ -6090,6 +6097,60 @@ func TestUIRemoteSyncSetupPersistsBindingAfterSuccessfulPush(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUIRemoteSyncSetupCanPersistManualSyncMode(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key := vault.MasterKey{Password: "correct horse battery staple"}
|
||||||
|
currentPath := filepath.Join(t.TempDir(), "current.kdbx")
|
||||||
|
writeKDBXMainTestFile(t, currentPath, vault.Model{
|
||||||
|
Entries: []vault.Entry{{ID: "entry-current", Title: "Vault Console", Path: []string{"Root", "Internet"}}},
|
||||||
|
}, key)
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
case http.MethodPut:
|
||||||
|
w.Header().Set("ETag", "\"v1\"")
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected method %s", r.Method)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
u := newUIWithSession("desktop", &session.Manager{}, statePaths{
|
||||||
|
DefaultSaveAsPath: filepath.Join(dir, "vault.kdbx"),
|
||||||
|
RecentVaultsPath: filepath.Join(dir, "recent-vaults.json"),
|
||||||
|
RecentRemotesPath: filepath.Join(dir, "recent-remotes.json"),
|
||||||
|
UIPreferencesPath: filepath.Join(dir, "ui-prefs.json"),
|
||||||
|
})
|
||||||
|
u.masterPassword.SetText(key.Password)
|
||||||
|
u.vaultPath.SetText(currentPath)
|
||||||
|
if err := u.openVaultAction(); err != nil {
|
||||||
|
t.Fatalf("openVaultAction() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
u.openRemoteSyncSetupDialog()
|
||||||
|
u.syncSetupAutomatic.Value = false
|
||||||
|
u.syncRemoteBaseURL.SetText(server.URL)
|
||||||
|
u.syncRemotePath.SetText("vaults/manual.kdbx")
|
||||||
|
u.syncRemoteUsername.SetText("tjulian")
|
||||||
|
u.syncRemotePassword.SetText("token-1")
|
||||||
|
|
||||||
|
if err := u.advancedSyncAction(); err != nil {
|
||||||
|
t.Fatalf("advancedSyncAction() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := u.selectedVaultRemoteSyncMode; got != appstate.SyncModeManual {
|
||||||
|
t.Fatalf("selectedVaultRemoteSyncMode = %q, want manual", got)
|
||||||
|
}
|
||||||
|
if got := u.recentRemotes[0].SyncMode; got != string(appstate.SyncModeManual) {
|
||||||
|
t.Fatalf("recentRemotes[0].SyncMode = %q, want manual", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUISaveCurrentRemoteBindingActionPersistsBindingIntoVault(t *testing.T) {
|
func TestUISaveCurrentRemoteBindingActionPersistsBindingIntoVault(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user