diff --git a/frontend/src/components/sftp/FileTree.vue b/frontend/src/components/sftp/FileTree.vue index 72bad14..9708f55 100644 --- a/frontend/src/components/sftp/FileTree.vue +++ b/frontend/src/components/sftp/FileTree.vue @@ -21,6 +21,7 @@ @@ -28,8 +29,10 @@ @@ -39,6 +42,7 @@ @@ -54,8 +58,10 @@ @@ -63,6 +69,14 @@ + + + @@ -81,6 +95,8 @@ v-for="entry in entries" :key="entry.path" class="w-full flex items-center gap-2 px-3 py-1.5 hover:bg-[var(--wraith-bg-tertiary)] transition-colors cursor-pointer group" + :class="{ 'bg-[var(--wraith-bg-tertiary)] ring-1 ring-inset ring-[var(--wraith-accent-blue)]': selectedEntry?.path === entry.path }" + @click="selectedEntry = entry" @dblclick="handleEntryDblClick(entry)" > @@ -135,7 +151,12 @@ diff --git a/frontend/src/composables/useTransfers.ts b/frontend/src/composables/useTransfers.ts new file mode 100644 index 0000000..c8378f1 --- /dev/null +++ b/frontend/src/composables/useTransfers.ts @@ -0,0 +1,40 @@ +import { ref } from "vue"; + +export interface Transfer { + id: string; + fileName: string; + percentage: number; + speed: string; + direction: "upload" | "download"; +} + +// Module-level singleton — shared across all components that import this composable. +const transfers = ref([]); + +let _nextId = 0; + +function addTransfer(fileName: string, direction: "upload" | "download"): string { + const id = `transfer-${++_nextId}`; + transfers.value.push({ id, fileName, percentage: 0, speed: "", direction }); + return id; +} + +function completeTransfer(id: string): void { + const t = transfers.value.find((t) => t.id === id); + if (t) { + t.percentage = 100; + t.speed = ""; + } + // Remove after 3 seconds + setTimeout(() => { + transfers.value = transfers.value.filter((t) => t.id !== id); + }, 3000); +} + +function failTransfer(id: string): void { + transfers.value = transfers.value.filter((t) => t.id !== id); +} + +export function useTransfers() { + return { transfers, addTransfer, completeTransfer, failTransfer }; +}