wraith/src/components/sftp/TransferProgress.vue
Vantz Stockwell b86e2d68d8 refactor: extract keyboard shortcuts composable + 5 UX bug fixes
- Extract handleKeydown into useKeyboardShortcuts.ts composable; reduces
  MainLayout by ~20 lines and isolates keyboard logic cleanly
- ConnectionTree: watch groups for additions and auto-expand new entries
- MonitorBar: generation counter prevents stale event listeners on rapid
  tab switching
- NetworkScanner: revoke blob URL after CSV export click (memory leak)
- TransferProgress: implement the auto-expand/collapse watcher that was
  only commented but never wired up
- FileTree: block binary/large file uploads with clear user error rather
  than silently corrupting — backend sftp_write_file is text-only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 16:53:46 -04:00

67 lines
2.4 KiB
Vue

<template>
<div class="border-t border-[var(--wraith-border)]">
<!-- Header -->
<button
class="w-full flex items-center justify-between px-3 py-1.5 text-xs text-[var(--wraith-text-muted)] hover:bg-[var(--wraith-bg-tertiary)] transition-colors cursor-pointer"
@click="expanded = !expanded"
>
<span>Transfers ({{ transfers.length }})</span>
<svg
class="w-3 h-3 transition-transform"
:class="{ 'rotate-180': expanded }"
viewBox="0 0 16 16"
fill="currentColor"
>
<path d="M12.78 5.22a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L3.22 6.28a.75.75 0 0 1 1.06-1.06L8 8.94l3.72-3.72a.75.75 0 0 1 1.06 0z" />
</svg>
</button>
<!-- Transfer list -->
<div v-if="expanded && transfers.length > 0" class="px-3 pb-2">
<div
v-for="transfer in transfers"
:key="transfer.id"
class="flex flex-col gap-1 py-1.5"
>
<div class="flex items-center justify-between text-xs">
<span class="text-[var(--wraith-text-secondary)] truncate">
{{ transfer.fileName }}
</span>
<span class="text-[var(--wraith-text-muted)] shrink-0 ml-2">
{{ transfer.speed }}
</span>
</div>
<div class="w-full h-1.5 bg-[var(--wraith-bg-tertiary)] rounded-full overflow-hidden">
<div
class="h-full rounded-full transition-all duration-300"
:class="transfer.direction === 'upload' ? 'bg-[var(--wraith-accent-blue)]' : 'bg-[var(--wraith-accent-green)]'"
:style="{ width: transfer.percentage + '%' }"
/>
</div>
<div class="text-[10px] text-[var(--wraith-text-muted)]">
{{ transfer.percentage }}% - {{ transfer.direction === 'upload' ? 'Uploading' : 'Downloading' }}
</div>
</div>
</div>
<!-- Empty state -->
<div v-if="expanded && transfers.length === 0" class="px-3 py-2 text-xs text-[var(--wraith-text-muted)]">
No active transfers
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
import { useTransfers } from "@/composables/useTransfers";
const expanded = ref(false);
const { transfers } = useTransfers();
// Auto-expand when transfers become active, collapse when all are gone
watch(() => transfers.value.length, (newLen, oldLen) => {
if (newLen > 0 && oldLen === 0) expanded.value = true;
if (newLen === 0) expanded.value = false;
});
</script>