feat: add Peer Files UI for browsing and downloading federated content

- New PeerFiles.vue view shows federated peers and their shared catalogs
- Peer Files card in Cloud.vue shows when federation peers exist
- New content.download-peer RPC fetches content from peer via Tor
- Route: /dashboard/cloud/peers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-13 02:37:59 +00:00
parent bd7911843d
commit 2e20984686
6 changed files with 375 additions and 2 deletions

View File

@@ -58,6 +58,36 @@
</div>
</div>
<!-- Peer Files Card -->
<div
v-if="hasFederatedPeers"
data-controller-container
tabindex="0"
class="glass-card p-6 cursor-pointer transition-all hover:-translate-y-1 hover:bg-white/10 mt-4"
@click="router.push({ name: 'peer-files' })"
>
<div class="flex items-center gap-4 mb-4">
<div class="flex-shrink-0 w-12 h-12 rounded-xl flex items-center justify-center bg-purple-500/15">
<svg class="w-7 h-7 text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
</svg>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-semibold text-white mb-0.5 truncate">Peer Files</h3>
<p class="text-xs text-white/50">Browse files shared by federated nodes</p>
</div>
<svg class="w-5 h-5 text-white/30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</div>
<div class="flex items-center gap-2 text-xs">
<span class="inline-flex items-center gap-1.5 px-2 py-1 rounded-full bg-purple-500/15 text-purple-400">
<span class="w-1.5 h-1.5 rounded-full bg-purple-400"></span>
{{ peerCount }} peers
</span>
</div>
</div>
<!-- Not Installed Hint -->
<div v-if="!fileBrowserRunning" class="glass-card p-8 mt-6 text-center">
<p class="text-white/60 mb-3">Install File Browser from the App Store to get started with your cloud storage.</p>
@@ -73,11 +103,14 @@ import { computed, ref, onMounted } from 'vue'
import { useRouter, RouterLink } from 'vue-router'
import { useAppStore } from '../stores/app'
import { fileBrowserClient } from '@/api/filebrowser-client'
import { rpcClient } from '@/api/rpc-client'
const router = useRouter()
const store = useAppStore()
const sectionCounts = ref<Record<string, number>>({})
const countsLoading = ref(false)
const peerCount = ref(0)
const hasFederatedPeers = computed(() => peerCount.value > 0)
const APP_ALIASES: Record<string, string[]> = {
immich: ['immich_server', 'immich-server'],
@@ -182,7 +215,19 @@ async function loadCounts() {
}
}
onMounted(() => loadCounts())
onMounted(() => {
loadCounts()
loadPeerCount()
})
async function loadPeerCount() {
try {
const result = await rpcClient.federationListNodes()
peerCount.value = result?.nodes?.length ?? 0
} catch {
peerCount.value = 0
}
}
function openSection(section: ContentSection) {
router.push({ name: 'cloud-folder', params: { folderId: section.id } })