Files
oxspeak/src/pages/config.vue
2026-03-24 17:44:44 +01:00

241 lines
8.1 KiB
Vue

<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>