diff --git a/src-tauri/src/credentials/record.rs b/src-tauri/src/credentials/record.rs
index e7d1745..96b837c 100644
--- a/src-tauri/src/credentials/record.rs
+++ b/src-tauri/src/credentials/record.rs
@@ -21,6 +21,7 @@ use super::{
Credential,
Crypto,
PersistentCredential,
+ SshKey,
};
@@ -48,6 +49,7 @@ impl CredentialRecord {
pub async fn save(&self, crypto: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError> {
let type_name = match &self.credential {
Credential::AwsBase(_) => AwsBaseCredential::type_name(),
+ Credential::Ssh(_) => SshKey::type_name(),
_ => return Err(SaveCredentialsError::NotPersistent),
};
@@ -82,6 +84,7 @@ impl CredentialRecord {
// save credential details to child table
match &self.credential {
Credential::AwsBase(b) => b.save_details(&self.id, crypto, &mut txn).await,
+ Credential::Ssh(s) => s.save_details(&self.id, crypto, &mut txn).await,
_ => Err(SaveCredentialsError::NotPersistent),
}?;
@@ -147,6 +150,11 @@ impl CredentialRecord {
.ok_or(LoadCredentialsError::InvalidData)?;
records.push(Self::from_parts(parent, credential));
}
+ for (id, credential) in SshKey::list(crypto, pool).await? {
+ let parent = parent_map.remove(&id)
+ .ok_or(LoadCredentialsError::InvalidData)?;
+ records.push(Self::from_parts(parent, credential));
+ }
Ok(records)
}
diff --git a/src/lib/errors.js b/src/lib/errors.js
index 13eef7e..a42cb59 100644
--- a/src/lib/errors.js
+++ b/src/lib/errors.js
@@ -6,3 +6,12 @@ export function getRootCause(error) {
return error;
}
}
+
+
+export function fullMessage(error) {
+ let msg = error?.msg ? error.msg : error;
+ if (error.source) {
+ msg = `${msg}: ${fullMessage(error.source)}`;
+ }
+ return msg
+}
diff --git a/src/ui/ErrorAlert.svelte b/src/ui/ErrorAlert.svelte
index aa09adb..6465f71 100644
--- a/src/ui/ErrorAlert.svelte
+++ b/src/ui/ErrorAlert.svelte
@@ -2,6 +2,9 @@
import { onMount } from 'svelte';
import { slide } from 'svelte/transition';
+ import { fullMessage } from '../lib/errors.js';
+
+
let extraClasses = "";
export {extraClasses as class};
export let slideDuration = 150;
@@ -78,7 +81,7 @@
- {error.msg || error}
+ {fullMessage(error)}
{#if $$slots.buttons}
diff --git a/src/ui/FileInput.svelte b/src/ui/FileInput.svelte
index 8e5f659..49b2bed 100644
--- a/src/ui/FileInput.svelte
+++ b/src/ui/FileInput.svelte
@@ -1,20 +1,33 @@
@@ -59,7 +72,11 @@
{#if awsRecords.length > 0}
{#each awsRecords as record (record.id)}
-
+
{/each}
@@ -83,12 +100,12 @@
{#if sshRecords.length > 0}
{#each sshRecords as record (record.id)}
- {#if record.isNew}
- console.log(e)} />
- {:else}
-
- {/if}
+
{/each}
+
+
+ Add
+
{:else if records !== null}
You have no saved SSH keys.
@@ -101,3 +118,5 @@
+
+
diff --git a/src/views/credentials/AwsCredential.svelte b/src/views/credentials/AwsCredential.svelte
index c4aa001..a99f98b 100644
--- a/src/views/credentials/AwsCredential.svelte
+++ b/src/views/credentials/AwsCredential.svelte
@@ -31,36 +31,11 @@
showDetails = false;
}
- let deleteModal;
- function conditionalDelete() {
- if (!record.isNew) {
- deleteModal.showModal();
- }
- else {
- deleteCredential();
- }
- }
-
- async function deleteCredential() {
- try {
- if (!record.isNew) {
- await invoke('delete_credential', {id: record.id});
- }
- dispatch('update');
- }
- catch (e) {
- showDetails = true;
- // wait for showDetails to take effect and the alert to be rendered
- window.setTimeout(() => alert.setError(e), 0);
- }
- }
+
-
+
{#if !record?.isNew && showDetails}
@@ -85,7 +60,7 @@
dispatch('delete', record)}
>
@@ -141,20 +116,4 @@
{/if}
-
-
-
-
Delete AWS credential "{record.name}"?
-
-
-
-
-
diff --git a/src/views/credentials/ConfirmDelete.svelte b/src/views/credentials/ConfirmDelete.svelte
new file mode 100644
index 0000000..4960626
--- /dev/null
+++ b/src/views/credentials/ConfirmDelete.svelte
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+ {#if record}
+ Delete {credentialDescription(record)} "{record.name}"?
+ {/if}
+
+
+
+
+
+
diff --git a/src/views/credentials/EditSshKey.svelte b/src/views/credentials/EditSshKey.svelte
new file mode 100644
index 0000000..5f29307
--- /dev/null
+++ b/src/views/credentials/EditSshKey.svelte
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/credentials/NewSshKey.svelte b/src/views/credentials/NewSshKey.svelte
index a337c43..8e19682 100644
--- a/src/views/credentials/NewSshKey.svelte
+++ b/src/views/credentials/NewSshKey.svelte
@@ -2,12 +2,12 @@
import { createEventDispatcher } from 'svelte';
import { invoke } from '@tauri-apps/api/core';
import { homeDir } from '@tauri-apps/api/path';
- import { fade, slide } from 'svelte/transition';
+ import { fade } from 'svelte/transition';
import ErrorAlert from '../../ui/ErrorAlert.svelte';
import FileInput from '../../ui/FileInput.svelte';
- import Icon from '../../ui/Icon.svelte';
import PassphraseInput from '../../ui/PassphraseInput.svelte';
+ import Spinner from '../../ui/Spinner.svelte';
export let record;
@@ -22,71 +22,59 @@
homeDir().then(d => defaultPath = `${d}/.ssh`);
let alert;
+ let saving = false;
async function saveCredential() {
- let key = await invoke('sshkey_from_file', {path: file.path, passphrase});
- dispatch('update', key);
+ saving = true;
+ try {
+ let key = await invoke('sshkey_from_file', {path: file.path, passphrase});
+ const payload = {
+ id: record.id,
+ name,
+ is_default: false, // ssh keys don't care about defaults
+ credential: {type: 'Ssh', ...key},
+ };
+ await invoke('save_credential', {record: payload});
+ dispatch('save', payload);
+ }
+ finally {
+ saving = false;
+ }
}
-
-
-
- showDetails = !showDetails}
- >
-
-
- dispatch('update')}
- >
-
-
-
+
+
\ No newline at end of file
diff --git a/src/views/credentials/SshKey.svelte b/src/views/credentials/SshKey.svelte
index e2febdf..ed474a9 100644
--- a/src/views/credentials/SshKey.svelte
+++ b/src/views/credentials/SshKey.svelte
@@ -1,46 +1,45 @@
-
+
-
{record.name || ''}
+ {#if !record.isNew}
+ {#if showDetails}
+
+ {:else}
+
+ {record.name}
+
+ {/if}
+ {/if}
dispatch('delete', record)}
>
- {#if showDetails}
-
+ {#if record && showDetails}
+
+ {#if record.isNew}
+
+ {:else}
+
+ {/if}
+
{/if}
-
\ No newline at end of file
+