pré-rework
This commit is contained in:
240
src/pages/config.vue
Normal file
240
src/pages/config.vue
Normal file
@@ -0,0 +1,240 @@
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref} from 'vue'
|
||||
import {createConfigClient} from '../config'
|
||||
|
||||
// --- Types ---
|
||||
// Ils sont maintenant importés ou définis via l'interface du client
|
||||
|
||||
const configClient = createConfigClient()
|
||||
const config = ref<any>({
|
||||
servers: [],
|
||||
identities: []
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const toast = useToast()
|
||||
|
||||
const items = [{
|
||||
label: 'Serveurs',
|
||||
icon: 'i-lucide-server',
|
||||
slot: 'servers'
|
||||
}, {
|
||||
label: 'Identités',
|
||||
icon: 'i-lucide-user',
|
||||
slot: 'identities'
|
||||
}]
|
||||
|
||||
// --- Methods ---
|
||||
|
||||
async function fetchConfig() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await configClient.get()
|
||||
config.value = res
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la récupération de la config:', error)
|
||||
toast.add({title: 'Erreur', description: 'Impossible de charger la configuration.', color: 'red'})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function saveConfig() {
|
||||
loading.value = true
|
||||
try {
|
||||
await configClient.update(config.value)
|
||||
// Re-fetch config to get any auto-generated keys
|
||||
await fetchConfig()
|
||||
toast.add({title: 'Succès', description: 'Configuration sauvegardée.', color: 'green'})
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la sauvegarde de la config:', error)
|
||||
toast.add({title: 'Erreur', description: 'Impossible de sauvegarder la configuration.', color: 'red'})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// async function generateKey(index: number) {
|
||||
// try {
|
||||
// // Note: generate_ssh_key n'est pas encore dans IConfigClient, on peut l'ajouter si besoin
|
||||
// // ou garder un invoke direct si c'est spécifique à Tauri, mais ici on veut de l'abstrait.
|
||||
// // Pour le moment on utilise invoke car c'est un utilitaire.
|
||||
// const {invoke} from '@tauri-apps/api/core'
|
||||
// const key = await invoke<string>('generate_ssh_key')
|
||||
// config.value.identities[index].private_key = key
|
||||
// toast.add({title: 'Succès', description: 'Clé SSH générée.', color: 'green'})
|
||||
// } catch (error) {
|
||||
// console.error('Erreur lors de la génération de la clé:', error)
|
||||
// toast.add({title: 'Erreur', description: 'Impossible de générer la clé.', color: 'red'})
|
||||
// }
|
||||
// }
|
||||
|
||||
function addServer() {
|
||||
config.value.servers.push({adresse: '', identity: ''})
|
||||
}
|
||||
|
||||
function removeServer(index: number) {
|
||||
config.value.servers.splice(index, 1)
|
||||
}
|
||||
|
||||
function addIdentity() {
|
||||
config.value.identities.push({
|
||||
id: crypto.randomUUID(),
|
||||
username: '',
|
||||
private_key: '',
|
||||
mode: 'private_key_path'
|
||||
})
|
||||
}
|
||||
|
||||
function removeIdentity(index: number) {
|
||||
config.value.identities.splice(index, 1)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchConfig()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-6 max-w-4xl mx-auto overflow-y-auto h-full">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-2xl font-bold">Configuration</h1>
|
||||
<UButton
|
||||
icon="i-lucide-save"
|
||||
color="primary"
|
||||
:loading="loading"
|
||||
@click="saveConfig"
|
||||
>
|
||||
Sauvegarder
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<UTabs :items="items" class="w-full">
|
||||
<template #servers>
|
||||
<div class="space-y-4 py-4">
|
||||
<div v-for="(server, index) in config.servers" :key="index"
|
||||
class="p-4 border border-gray-200 dark:border-gray-800 rounded-lg relative bg-white dark:bg-gray-900 shadow-sm">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<UFormField label="Adresse du serveur (IP:Port)">
|
||||
<UInput v-model="server.adresse" placeholder="ex: 127.0.0.1:50051" class="w-full"/>
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Identité à utiliser">
|
||||
<USelect
|
||||
v-model="server.identity"
|
||||
:items="config.identities.map(i => ({ label: i.username || i.id, value: i.id }))"
|
||||
placeholder="Sélectionner une identité"
|
||||
class="w-full"
|
||||
/>
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<UButton
|
||||
icon="i-lucide-trash"
|
||||
color="red"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="absolute top-2 right-2"
|
||||
@click="removeServer(index)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<UButton
|
||||
icon="i-lucide-plus"
|
||||
variant="dashed"
|
||||
block
|
||||
@click="addServer"
|
||||
>
|
||||
Ajouter un serveur
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #identities>
|
||||
<div class="space-y-4 py-4">
|
||||
<div v-for="(identity, index) in config.identities" :key="identity.id"
|
||||
class="p-4 border border-gray-200 dark:border-gray-800 rounded-lg relative bg-white dark:bg-gray-900 shadow-sm">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<UFormField label="ID d'identité (unique)">
|
||||
<UInput v-model="identity.id" placeholder="ex: mon-id" class="w-full"/>
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Nom d'utilisateur">
|
||||
<UInput v-model="identity.username" placeholder="ex: MonPseudo" class="w-full"/>
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Mode d'authentification" class="md:col-span-2">
|
||||
<USelect
|
||||
v-model="identity.mode"
|
||||
:items="[
|
||||
{ label: 'Clé (Fichier)', value: 'private_key_path' },
|
||||
{ label: 'Clé (Base64)', value: 'private_key_base64' },
|
||||
{ label: 'Login uniquement', value: 'login' }
|
||||
]"
|
||||
class="w-full"
|
||||
/>
|
||||
</UFormField>
|
||||
|
||||
<template v-if="identity.mode === 'private_key_path' || identity.mode === 'private_key_base64'">
|
||||
<UFormField :label="identity.mode === 'private_key_path' ? 'Chemin de la clé' : 'Clé privée (Base64)'"
|
||||
class="md:col-span-2">
|
||||
<div class="space-y-2">
|
||||
<UTextarea
|
||||
v-model="identity.private_key"
|
||||
:placeholder="identity.mode === 'private_key_path' ? 'ex: ~/.ssh/id_rsa' : 'Entrez la clé encodée en base64 (Si vide, une clé sera générée au besoin)'"
|
||||
class="w-full"
|
||||
/>
|
||||
<!-- <UButton-->
|
||||
<!-- v-if="identity.mode === 'private_key_base64'"-->
|
||||
<!-- icon="i-lucide-key"-->
|
||||
<!-- variant="subtle"-->
|
||||
<!-- size="xs"-->
|
||||
<!-- label="Générer une clé SSH"-->
|
||||
<!-- @click="generateKey(index)"-->
|
||||
<!-- />-->
|
||||
</div>
|
||||
</UFormField>
|
||||
</template>
|
||||
|
||||
|
||||
<template v-if="identity.token">
|
||||
<UFormField label="Jeton JWT (Persistant)" class="md:col-span-2">
|
||||
<div class="flex gap-2">
|
||||
<UInput v-model="identity.token" readonly class="flex-1 font-mono text-xs"/>
|
||||
<UButton
|
||||
icon="i-lucide-copy"
|
||||
variant="ghost"
|
||||
color="neutral"
|
||||
@click="() => {
|
||||
navigator.clipboard.writeText(identity.token || '')
|
||||
toast.add({ title: 'Copié', description: 'Jeton JWT copié dans le presse-papier', color: 'green' })
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</UFormField>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<UButton
|
||||
icon="i-lucide-trash"
|
||||
color="red"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="absolute top-2 right-2"
|
||||
@click="removeIdentity(index)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<UButton
|
||||
icon="i-lucide-plus"
|
||||
variant="dashed"
|
||||
block
|
||||
@click="addIdentity"
|
||||
>
|
||||
Ajouter une identité
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UTabs>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user