add Docker credentials to management page
This commit is contained in:
parent
c6e22fc91b
commit
479a0a96eb
@ -1,4 +1,3 @@
|
|||||||
use sqlx::types::uuid::Uuid;
|
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
@ -7,7 +6,6 @@ use crate::credentials::{
|
|||||||
self,
|
self,
|
||||||
Credential,
|
Credential,
|
||||||
CredentialRecord,
|
CredentialRecord,
|
||||||
Crypto,
|
|
||||||
DockerCredential,
|
DockerCredential,
|
||||||
};
|
};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
@ -6,9 +6,8 @@
|
|||||||
|
|
||||||
import AwsCredential from './credentials/AwsCredential.svelte';
|
import AwsCredential from './credentials/AwsCredential.svelte';
|
||||||
import ConfirmDelete from './credentials/ConfirmDelete.svelte';
|
import ConfirmDelete from './credentials/ConfirmDelete.svelte';
|
||||||
|
import DockerCredential from './credentials/DockerCredential.svelte';
|
||||||
import SshKey from './credentials/SshKey.svelte';
|
import SshKey from './credentials/SshKey.svelte';
|
||||||
// import NewSshKey from './credentials/NewSshKey.svelte';
|
|
||||||
// import EditSshKey from './credentials/EditSshKey.svelte';
|
|
||||||
import Icon from '../ui/Icon.svelte';
|
import Icon from '../ui/Icon.svelte';
|
||||||
import Nav from '../ui/Nav.svelte';
|
import Nav from '../ui/Nav.svelte';
|
||||||
|
|
||||||
@ -16,6 +15,7 @@
|
|||||||
let records = null
|
let records = null
|
||||||
$: awsRecords = (records || []).filter(r => r.credential.type === 'AwsBase');
|
$: awsRecords = (records || []).filter(r => r.credential.type === 'AwsBase');
|
||||||
$: sshRecords = (records || []).filter(r => r.credential.type === 'Ssh');
|
$: sshRecords = (records || []).filter(r => r.credential.type === 'Ssh');
|
||||||
|
$: dockerRecords = (records || []).filter(r => r.credential.type === 'Docker');
|
||||||
|
|
||||||
let defaults = writable({});
|
let defaults = writable({});
|
||||||
async function loadCreds() {
|
async function loadCreds() {
|
||||||
@ -47,6 +47,17 @@
|
|||||||
records = records;
|
records = records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function newDocker() {
|
||||||
|
records.push({
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
name: null,
|
||||||
|
is_default: false,
|
||||||
|
credential: {type: 'Docker', ServerURL: '', Username: '', Secret: ''},
|
||||||
|
isNew: true,
|
||||||
|
});
|
||||||
|
records = records;
|
||||||
|
}
|
||||||
|
|
||||||
let confirmDelete;
|
let confirmDelete;
|
||||||
function handleDelete(evt) {
|
function handleDelete(evt) {
|
||||||
const record = evt.detail;
|
const record = evt.detail;
|
||||||
@ -117,6 +128,29 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-y-4">
|
||||||
|
<div class="divider">
|
||||||
|
<h2 class="text-xl font-bold">Docker credentials</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if dockerRecords.length > 0}
|
||||||
|
{#each dockerRecords as record (record.id)}
|
||||||
|
<DockerCredential {record} on:save={loadCreds} on:delete={handleDelete} />
|
||||||
|
{/each}
|
||||||
|
<button class="btn btn-primary btn-wide mx-auto" on:click={newDocker}>
|
||||||
|
<Icon name="plus-circle-mini" class="size-5" />
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
{:else if records !== null}
|
||||||
|
<div class="flex flex-col gap-6 items-center rounded-box border-2 border-dashed border-neutral-content/30 p-6">
|
||||||
|
<div>You have no saved Docker credentials.</div>
|
||||||
|
<button class="btn btn-primary btn-wide mx-auto" on:click={newSsh}>
|
||||||
|
<Icon name="plus-circle-mini" class="size-5" />
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ConfirmDelete bind:this={confirmDelete} on:confirm={loadCreds} />
|
<ConfirmDelete bind:this={confirmDelete} on:confirm={loadCreds} />
|
||||||
|
@ -5,13 +5,12 @@
|
|||||||
|
|
||||||
import ErrorAlert from '../../ui/ErrorAlert.svelte';
|
import ErrorAlert from '../../ui/ErrorAlert.svelte';
|
||||||
import Icon from '../../ui/Icon.svelte';
|
import Icon from '../../ui/Icon.svelte';
|
||||||
|
import PassphraseInput from '../../ui/PassphraseInput.svelte';
|
||||||
|
|
||||||
|
|
||||||
export let record;
|
export let record;
|
||||||
export let defaults;
|
export let defaults;
|
||||||
|
|
||||||
import PassphraseInput from '../../ui/PassphraseInput.svelte';
|
|
||||||
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
let showDetails = record.isNew ? true : false;
|
let showDetails = record.isNew ? true : false;
|
||||||
|
@ -26,9 +26,12 @@
|
|||||||
if (record.credential.type === 'AwsBase') {
|
if (record.credential.type === 'AwsBase') {
|
||||||
return 'AWS credential';
|
return 'AWS credential';
|
||||||
}
|
}
|
||||||
if (record.credential.type === 'Ssh') {
|
else if (record.credential.type === 'Ssh') {
|
||||||
return 'SSH key';
|
return 'SSH key';
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
return `${record.credential.type} credential`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
105
src/views/credentials/DockerCredential.svelte
Normal file
105
src/views/credentials/DockerCredential.svelte
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { fade, slide } from 'svelte/transition';
|
||||||
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
|
|
||||||
|
import ErrorAlert from '../../ui/ErrorAlert.svelte';
|
||||||
|
import Icon from '../../ui/Icon.svelte';
|
||||||
|
import PassphraseInput from '../../ui/PassphraseInput.svelte';
|
||||||
|
|
||||||
|
|
||||||
|
export let record;
|
||||||
|
|
||||||
|
let local = JSON.parse(JSON.stringify(record));
|
||||||
|
$: isModified = JSON.stringify(local) !== JSON.stringify(record);
|
||||||
|
let showDetails = record?.isNew;
|
||||||
|
|
||||||
|
let alert;
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
async function saveCredential() {
|
||||||
|
await invoke('save_credential', {record: local});
|
||||||
|
dispatch('save', local);
|
||||||
|
showDetails = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="rounded-box space-y-4 bg-base-200">
|
||||||
|
<div class="flex items-center px-6 py-4 gap-x-4">
|
||||||
|
{#if !record.isNew}
|
||||||
|
{#if showDetails}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered bg-transparent text-lg font-bold grow"
|
||||||
|
bind:value={local.name}
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<h3 class="text-lg font-bold break-all">
|
||||||
|
{record.name}
|
||||||
|
</h3>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="join ml-auto">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline join-item"
|
||||||
|
on:click={() => showDetails = !showDetails}
|
||||||
|
>
|
||||||
|
<Icon name="pencil" class="size-6" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline btn-error join-item"
|
||||||
|
on:click={() => dispatch('delete', record)}
|
||||||
|
>
|
||||||
|
<Icon name="trash" class="size-6" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if showDetails}
|
||||||
|
<form
|
||||||
|
transition:slide|local={{duration: 200}}
|
||||||
|
class=" px-6 pb-4 space-y-4"
|
||||||
|
on:submit|preventDefault={() => alert.run(saveCredential)}
|
||||||
|
>
|
||||||
|
<ErrorAlert bind:this={alert} />
|
||||||
|
|
||||||
|
<div class="grid grid-cols-[auto_1fr] items-center gap-4">
|
||||||
|
{#if record.isNew}
|
||||||
|
<span class="justify-self-end">Name</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered bg-transparent"
|
||||||
|
bind:value={local.name}
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<span class="justify-self-end">Server URL</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered font-mono bg-transparent"
|
||||||
|
bind:value={local.credential.ServerURL}
|
||||||
|
>
|
||||||
|
|
||||||
|
<span>Password</span>
|
||||||
|
<div class="font-mono">
|
||||||
|
<PassphraseInput class="bg-transparent" bind:value={local.credential.Secret} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end">
|
||||||
|
{#if isModified}
|
||||||
|
<button
|
||||||
|
transition:fade={{duration: 100}}
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-primary"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
</div>
|
Loading…
x
Reference in New Issue
Block a user