add link functionality to create public links (closes #213)

This commit is contained in:
FTCHD
2026-06-05 20:47:39 +03:00
parent 92bf0fcf5f
commit 1b3f1f4ae9
4 changed files with 99 additions and 3 deletions
+31
View File
@@ -113,6 +113,37 @@ export const SUPPORTS_ABOUT = [
'local',
] as const
export const SUPPORTS_LINK = [
'b2',
'box',
'drive',
'dropbox',
'fichier',
'filescom',
'gofile',
'imagekit',
'internetarchive',
'jottacloud',
'koofr',
'mailru',
'mega',
'onedrive',
'pikpak',
'pixeldrain',
'premiumizeme',
'pcloud',
's3',
'seafile',
'storj',
'sugarsync',
'yandex',
] as const
export function supportsPublicLink(backendType?: string | null): boolean {
if (!backendType) return false
return SUPPORTS_LINK.includes(backendType.toLowerCase() as any)
}
export const CANNOT_PERSIST_EMPTY_FOLDERS = [
's3',
'gcs',
+15 -2
View File
@@ -1,6 +1,6 @@
import { Button, Checkbox, Listbox, ListboxItem, cn } from '@heroui/react'
import { platform } from '@tauri-apps/plugin-os'
import { DownloadIcon, EyeIcon, PencilIcon, StarIcon, Trash2Icon } from 'lucide-react'
import { DownloadIcon, EyeIcon, PencilIcon, Share2Icon, StarIcon, Trash2Icon } from 'lucide-react'
import { useCallback } from 'react'
import { formatBytes } from '../../../lib/format.ts'
import FileIcon from './FileIcon'
@@ -24,6 +24,7 @@ export default function FileList({
favoritedKeys,
onToggleFavorite,
onDownload,
onShare,
onRename,
onDelete,
listHeight,
@@ -44,6 +45,7 @@ export default function FileList({
favoritedKeys?: Record<string, boolean>
onToggleFavorite?: (entry: Entry, isFavorited: boolean) => void
onDownload?: (entry: Entry) => void
onShare?: (entry: Entry) => void
onRename?: (entry: Entry) => void
onDelete?: (entry: Entry) => void
listHeight: number
@@ -162,7 +164,7 @@ export default function FileList({
}
const gridCols = showPreviewColumn
? 'grid-cols-[2.5rem_1fr_6rem_9rem_9rem]'
? 'grid-cols-[2.5rem_1fr_6rem_9rem_11rem]'
: 'grid-cols-[2.5rem_1fr_6rem_9rem_2.5rem]'
return (
@@ -298,6 +300,17 @@ export default function FileList({
<DownloadIcon className="size-5" />
</Button>
)}
{onShare && (
<Button
isIconOnly={true}
size="sm"
variant="light"
className="transition-opacity duration-300 opacity-0 group-hover:opacity-100"
onPress={() => onShare(entry)}
>
<Share2Icon className="size-4" />
</Button>
)}
{onRename && (
<Button
isIconOnly={true}
+19 -1
View File
@@ -1,4 +1,5 @@
import { Button, Divider, Tooltip } from '@heroui/react'
import { useQuery } from '@tanstack/react-query'
import { FolderPlusIcon } from 'lucide-react'
import {
forwardRef,
@@ -10,6 +11,8 @@ import {
useRef,
useState,
} from 'react'
import { supportsPublicLink } from '../../../lib/rclone/constants'
import rclone from '../../../lib/rclone/client'
import { useHostStore } from '../../../store/host.ts'
import FileList from './FileList'
import PanelToolbar, { type ToolbarButtons } from './PanelToolbar'
@@ -39,6 +42,7 @@ const FilePanel = forwardRef<
showPreviewColumn?: boolean
onPreviewRequest?: (item: Entry) => void
onDownload?: (item: Entry) => void
onShare?: (item: Entry) => void
onRename?: (item: Entry) => void
onDelete?: (item: Entry) => void
contextMenuItems?: ContextMenuItem[]
@@ -62,6 +66,7 @@ const FilePanel = forwardRef<
showPreviewColumn = true,
onPreviewRequest,
onDownload,
onShare,
onRename,
onDelete,
contextMenuItems,
@@ -84,6 +89,18 @@ const FilePanel = forwardRef<
isActive,
})
const remoteConfigQuery = useQuery({
queryKey: ['remote', nav.selectedRemote, 'config'],
queryFn: async () => {
return await rclone('/config/get', {
params: { query: { name: nav.selectedRemote! } },
})
},
enabled: nav.isRemote,
})
const canShare = supportsPublicLink(remoteConfigQuery.data?.type)
const { canCreateFolder, createFolder } = useCreateFolder(
nav.selectedRemote,
nav.cwd,
@@ -338,7 +355,7 @@ const FilePanel = forwardRef<
<div className="relative flex flex-col w-full h-full overflow-hidden">
<div
className={`sticky top-0 z-10 grid ${showPreviewColumn ? 'grid-cols-[2.5rem_1fr_6rem_9rem_9rem]' : 'grid-cols-[2.5rem_1fr_6rem_9rem_2.5rem]'} items-center py-2 bg-default-100`}
className={`sticky top-0 z-10 grid ${showPreviewColumn ? 'grid-cols-[2.5rem_1fr_6rem_9rem_11rem]' : 'grid-cols-[2.5rem_1fr_6rem_9rem_2.5rem]'} items-center py-2 bg-default-100`}
>
<div />
<div className="pl-2 font-semibold text-small">Name</div>
@@ -360,6 +377,7 @@ const FilePanel = forwardRef<
showPreviewColumn={showPreviewColumn}
onPreviewClick={handlePreviewClick}
onDownload={onDownload}
onShare={canShare ? onShare : undefined}
onRename={onRename}
onDelete={onDelete}
draggable={selectionMode === 'drag' || selectionMode === 'both'}
+34
View File
@@ -18,6 +18,7 @@ import {
} from '@heroui/react'
import { useMutation, useQuery } from '@tanstack/react-query'
import { invoke } from '@tauri-apps/api/core'
import { writeText } from '@tauri-apps/plugin-clipboard-manager'
import { ask, message, save } from '@tauri-apps/plugin-dialog'
import { platform } from '@tauri-apps/plugin-os'
import { AnimatePresence, motion } from 'framer-motion'
@@ -37,6 +38,7 @@ import { Group, Panel, Separator } from 'react-resizable-panels'
import { getFsInfo } from '../../lib/format'
// import { Document, Page, pdfjs } from 'react-pdf'
import { formatBytes } from '../../lib/format.ts'
import notify from '../../lib/notify'
import { startCopy, startMove } from '../../lib/rclone/api'
import rclone from '../../lib/rclone/client'
import { openWindow } from '../../lib/window'
@@ -214,6 +216,36 @@ export default function Browser() {
}
}, [])
const handleShare = useCallback(async (entry: Entry) => {
try {
const { root, filePath } = getFsInfo(entry.fullPath)
const result = await rclone('/operations/publiclink', {
params: {
query: {
fs: root,
remote: filePath,
},
},
})
if (result?.url) {
await writeText(result.url)
await notify({
title: 'Link Copied',
body: `Public link for "${entry.name}" copied to clipboard`,
})
}
} catch (error) {
await message(
error instanceof Error ? error.message : 'Failed to generate public link',
{
title: 'Share Error',
kind: 'error',
okLabel: 'OK',
}
)
}
}, [])
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'r' && (e.metaKey || e.ctrlKey)) {
@@ -249,6 +281,7 @@ export default function Browser() {
showPreviewColumn={true}
onDrop={(items, dest) => handleDrop(items, dest, 'left')}
onDownload={handleDownload}
onShare={handleShare}
onRename={handleRename}
onDelete={handleDelete}
allowedKeys={['REMOTES', 'LOCAL_FS', 'FAVORITES']}
@@ -269,6 +302,7 @@ export default function Browser() {
showPreviewColumn={true}
onDrop={(items, dest) => handleDrop(items, dest, 'right')}
onDownload={handleDownload}
onShare={handleShare}
onRename={handleRename}
onDelete={handleDelete}
allowedKeys={['REMOTES', 'LOCAL_FS', 'FAVORITES']}