Files
FanKarr/src/components/setup/SetupClientStep.vue
T

154 lines
5.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="flex flex-col gap-6">
<div v-if="!loaded" class="flex items-center justify-center py-10">
<div class="w-4 h-4 border border-border border-t-accent rounded-full animate-spin" />
</div>
<template v-else>
<div v-if="clients.length > 0" class="flex flex-col gap-2">
<div v-for="client in clients" :key="client.uuid" class="card flex items-center gap-3">
<span
class="w-2 h-2 rounded-full shrink-0"
:class="health[client.uuid] === true ? 'bg-ok' : health[client.uuid] === false ? 'bg-err' : 'bg-border'"
/>
<div class="flex-1 min-w-0">
<p class="text-sm text-primary font-medium truncate">{{ client.name }}</p>
<p class="text-meta text-muted mt-0.5">
{{ labelOf(client.type) }}
<template v-if="health[client.uuid] === false"> · <span class="text-err">injoignable</span></template>
<template v-else-if="health[client.uuid] === true"> · <span class="text-ok">connecté</span></template>
</p>
</div>
<button @click="edit(client)" class="btn-ghost btn-sm">Modifier</button>
</div>
</div>
<div v-if="formOpen" class="card flex flex-col gap-4">
<p class="text-sm font-semibold text-primary">{{ editing ? 'Modifier le client' : 'Ajouter un client' }}</p>
<TorrentClientForm
:key="formKey"
:client="editing"
:definitions="definitions"
:show-cancel="clients.length > 0"
@saved="onSaved"
@cancel="formOpen = false"
/>
</div>
<button v-else @click="add" class="btn-secondary self-start flex items-center gap-1.5">
<Plus :size="14" /> {{ clients.length > 0 ? 'Ajouter un autre client' : 'Ajouter un client' }}
</button>
<div class="flex items-start gap-3 px-4 py-3 rounded-field border border-border bg-card/50">
<Info :size="15" class="text-muted mt-0.5 shrink-0" />
<p class="text-meta text-muted leading-relaxed">
Le client doit enregistrer ses téléchargements dans un dossier que FanKarr voit
<template v-if="settings.completePath">(<span class="text-secondary">{{ settings.completePath }}</span>)</template>.
S'il tourne sur une autre machine ou dans un autre conteneur, renseignez
<span class="text-secondary">Chemin distant</span> et <span class="text-secondary">Chemin local</span>
dans les paramètres avancés du client.
</p>
</div>
<div v-if="warnSkip" class="flex items-start gap-3 px-4 py-3 rounded-field border border-accent/30 bg-accent/5" role="alert">
<TriangleAlert :size="15" class="text-accent mt-0.5 shrink-0" />
<div class="flex flex-col gap-0.5">
<p class="text-body text-accent font-medium">Aucun client configuré</p>
<p class="text-meta text-muted">
Sans client, FanKarr ne pourra rien télécharger. Cliquez à nouveau sur « Suivant » pour passer cette étape.
Vous pourrez en ajouter un plus tard dans Paramètres › Clients torrent.
</p>
</div>
</div>
</template>
</div>
</template>
<script setup lang="ts">
import { ref, inject, onMounted } from 'vue'
import { Info, Plus, TriangleAlert } from 'lucide-vue-next'
import TorrentClientForm from '@/components/settings/TorrentClientForm.vue'
import { setupContextKey, type SetupSettings } from './setup'
import type { SavedTorrentClient, TorrentClientDefinition } from '@/types/torrent-client'
defineProps<{ settings: SetupSettings; isDocker: boolean; defaultPath: string }>()
const context = inject(setupContextKey)!
const loaded = ref(false)
const clients = ref<SavedTorrentClient[]>([])
const definitions = ref<TorrentClientDefinition[]>([])
const health = ref<Record<string, boolean | null>>({})
const formOpen = ref(false)
const formKey = ref(0)
const editing = ref<SavedTorrentClient | null>(null)
const warnSkip = ref(false)
function labelOf(type: string) {
return definitions.value.find(d => d.id === type)?.label ?? type
}
async function refreshHealth(uuid: string) {
health.value[uuid] = null
try {
const res = await fetch(`/api/torrent-clients/${uuid}/healthcheck`, { credentials: 'include' })
health.value[uuid] = res.ok ? (await res.json()).online : false
} catch {
health.value[uuid] = false
}
}
function add() {
editing.value = null
formKey.value++
formOpen.value = true
}
function edit(client: SavedTorrentClient) {
editing.value = client
formKey.value++
formOpen.value = true
}
function onSaved(client: SavedTorrentClient, isEdit: boolean) {
if (isEdit) {
const i = clients.value.findIndex(c => c.uuid === client.uuid)
if (i !== -1) clients.value[i] = client
} else {
clients.value.push(client)
}
formOpen.value = false
warnSkip.value = false
context.clientSkipped = false
refreshHealth(client.uuid)
}
async function submit(): Promise<boolean> {
if (clients.value.length > 0) {
context.clientSkipped = false
return true
}
if (!warnSkip.value) {
warnSkip.value = true
return false
}
context.clientSkipped = true
return true
}
onMounted(async () => {
const [clientsRes, defsRes] = await Promise.all([
fetch('/api/torrent-clients', { credentials: 'include' }),
fetch('/api/torrent-clients/available', { credentials: 'include' }),
])
if (clientsRes.ok) clients.value = await clientsRes.json()
if (defsRes.ok) definitions.value = await defsRes.json()
for (const c of clients.value) refreshHealth(c.uuid)
formOpen.value = clients.value.length === 0
loaded.value = true
})
defineExpose({ submit })
</script>