fix: broken dir path breadcrumb links

This commit is contained in:
2025-10-05 15:01:55 +00:00
parent 33b235517c
commit b654f50ddd
5 changed files with 48 additions and 18 deletions

View File

@@ -6,14 +6,13 @@ import type {
import * as Err from "./error" import * as Err from "./error"
import { import {
type DirectoryHandle, type DirectoryHandle,
type FilePath, type DirectoryPath,
type FileSystemItem, type FileSystemItem,
FileType, FileType,
newDirectoryHandle, newDirectoryHandle,
type ReverseFilePath,
} from "./filesystem" } from "./filesystem"
export type DirectoryInfo = Doc<"directories"> & { path: FilePath } export type DirectoryInfo = Doc<"directories"> & { path: DirectoryPath }
export async function fetchRoot(ctx: AuthenticatedQueryCtx) { export async function fetchRoot(ctx: AuthenticatedQueryCtx) {
return await ctx.db return await ctx.db
@@ -50,7 +49,7 @@ export async function fetch(
) )
} }
const path: ReverseFilePath = [ const path: DirectoryPath = [
{ {
handle: newDirectoryHandle(directoryId), handle: newDirectoryHandle(directoryId),
name: directory.name, name: directory.name,
@@ -70,7 +69,7 @@ export async function fetch(
} }
} }
return { ...directory, path: path.reverse() as FilePath } return { ...directory, path: path.reverse() as DirectoryPath }
} }
export async function fetchContent( export async function fetchContent(

View File

@@ -29,6 +29,10 @@ export type FilePathComponent = {
name: string name: string
} }
export type PathComponent = FilePathComponent | DirectoryPathComponent export type PathComponent = FilePathComponent | DirectoryPathComponent
export type DirectoryPath = [
DirectoryPathComponent,
...DirectoryPathComponent[],
]
export type FilePath = [...DirectoryPathComponent[], PathComponent] export type FilePath = [...DirectoryPathComponent[], PathComponent]
export type ReverseFilePath = [PathComponent, ...DirectoryPathComponent[]] export type ReverseFilePath = [PathComponent, ...DirectoryPathComponent[]]
@@ -154,10 +158,8 @@ export async function restoreItems(
{ handles }: { handles: FileSystemHandle[] }, { handles }: { handles: FileSystemHandle[] },
) { ) {
// Collect all items to restore (including nested items) // Collect all items to restore (including nested items)
const { fileHandles, directoryHandles } = await collectAllHandlesRecursively( const { fileHandles, directoryHandles } =
ctx, await collectAllHandlesRecursively(ctx, { handles })
{ handles },
)
// Restore files and directories by unsetting deletedAt // Restore files and directories by unsetting deletedAt
const [filesResult, directoriesResult] = await Promise.all([ const [filesResult, directoriesResult] = await Promise.all([
@@ -183,8 +185,10 @@ export async function deleteItemsPermanently(
{ handles }: { handles: FileSystemHandle[] }, { handles }: { handles: FileSystemHandle[] },
) { ) {
// Collect all items to delete (including nested items) // Collect all items to delete (including nested items)
const { fileHandles: fileHandlesToDelete, directoryHandles: directoryHandlesToDelete } = const {
await collectAllHandlesRecursively(ctx, { handles }) fileHandles: fileHandlesToDelete,
directoryHandles: directoryHandlesToDelete,
} = await collectAllHandlesRecursively(ctx, { handles })
// Delete files and directories using their respective models // Delete files and directories using their respective models
const [filesResult, directoriesResult] = await Promise.all([ const [filesResult, directoriesResult] = await Promise.all([

View File

@@ -1,6 +1,7 @@
import type { Id } from "@fileone/convex/_generated/dataModel"
import type { import type {
DirectoryHandle, DirectoryHandle,
PathComponent, DirectoryPathComponent,
} from "@fileone/convex/model/filesystem" } from "@fileone/convex/model/filesystem"
import { Link } from "@tanstack/react-router" import { Link } from "@tanstack/react-router"
import { Fragment, useContext } from "react" import { Fragment, useContext } from "react"
@@ -22,7 +23,13 @@ import { cn } from "../../lib/utils"
import { DirectoryPageContext } from "./context" import { DirectoryPageContext } from "./context"
import { dragInfoAtom } from "./state" import { dragInfoAtom } from "./state"
export function FilePathBreadcrumb({ rootLabel }: { rootLabel: string }) { export function FilePathBreadcrumb({
rootLabel,
directoryUrlFn,
}: {
rootLabel: string
directoryUrlFn: (directory: Id<"directories">) => string
}) {
const { rootDirectory, directory } = useContext(DirectoryPageContext) const { rootDirectory, directory } = useContext(DirectoryPageContext)
const breadcrumbItems: React.ReactNode[] = [] const breadcrumbItems: React.ReactNode[] = []
@@ -33,6 +40,7 @@ export function FilePathBreadcrumb({ rootLabel }: { rootLabel: string }) {
<FilePathBreadcrumbItem <FilePathBreadcrumbItem
component={directory.path[i]!} component={directory.path[i]!}
rootLabel={rootLabel} rootLabel={rootLabel}
directoryUrlFn={directoryUrlFn}
/> />
</Fragment>, </Fragment>,
) )
@@ -49,6 +57,7 @@ export function FilePathBreadcrumb({ rootLabel }: { rootLabel: string }) {
<FilePathBreadcrumbItem <FilePathBreadcrumbItem
component={directory.path[0]!} component={directory.path[0]!}
rootLabel={rootLabel} rootLabel={rootLabel}
directoryUrlFn={directoryUrlFn}
/> />
)} )}
{breadcrumbItems} {breadcrumbItems}
@@ -64,9 +73,11 @@ export function FilePathBreadcrumb({ rootLabel }: { rootLabel: string }) {
function FilePathBreadcrumbItem({ function FilePathBreadcrumbItem({
component, component,
rootLabel, rootLabel,
directoryUrlFn,
}: { }: {
component: PathComponent component: DirectoryPathComponent
rootLabel: string rootLabel: string
directoryUrlFn: (directory: Id<"directories">) => string
}) { }) {
const { isDraggedOver, dropHandlers } = useFileDrop({ const { isDraggedOver, dropHandlers } = useFileDrop({
destItem: component.handle as DirectoryHandle, destItem: component.handle as DirectoryHandle,
@@ -83,7 +94,7 @@ function FilePathBreadcrumbItem({
{...dropHandlers} {...dropHandlers}
> >
<BreadcrumbLink asChild> <BreadcrumbLink asChild>
<Link to={`/directories/${component.handle.id}`}> <Link to={directoryUrlFn(component.handle.id)}>
{dirName} {dirName}
</Link> </Link>
</BreadcrumbLink> </BreadcrumbLink>

View File

@@ -104,6 +104,11 @@ function RouteComponent() {
[], [],
) )
const directoryUrlById = useCallback(
(directoryId: Id<"directories">) => `/directories/${directoryId}`,
[],
)
const handleContextMenuRequest = ( const handleContextMenuRequest = (
row: Row<FileSystemItem>, row: Row<FileSystemItem>,
table: Table<FileSystemItem>, table: Table<FileSystemItem>,
@@ -126,7 +131,10 @@ function RouteComponent() {
value={{ rootDirectory, directory, directoryContent }} value={{ rootDirectory, directory, directoryContent }}
> >
<header className="flex py-2 shrink-0 items-center gap-2 border-b px-4 w-full"> <header className="flex py-2 shrink-0 items-center gap-2 border-b px-4 w-full">
<FilePathBreadcrumb rootLabel="All Files" /> <FilePathBreadcrumb
rootLabel="All Files"
directoryUrlFn={directoryUrlById}
/>
<div className="ml-auto flex flex-row gap-2"> <div className="ml-auto flex flex-row gap-2">
<NewDirectoryItemDropdown /> <NewDirectoryItemDropdown />
<UploadFileButton /> <UploadFileButton />

View File

@@ -11,7 +11,7 @@ import {
useMutation as useConvexMutation, useMutation as useConvexMutation,
useQuery as useConvexQuery, useQuery as useConvexQuery,
} from "convex/react" } from "convex/react"
import { atom, useAtom, useAtomValue, useSetAtom, useStore } from "jotai" import { atom, useAtom, useSetAtom, useStore } from "jotai"
import { ShredderIcon, TrashIcon, UndoIcon } from "lucide-react" import { ShredderIcon, TrashIcon, UndoIcon } from "lucide-react"
import { useCallback, useEffect } from "react" import { useCallback, useEffect } from "react"
import { toast } from "sonner" import { toast } from "sonner"
@@ -75,6 +75,11 @@ function RouteComponent() {
[], [],
) )
const directoryUrlById = useCallback(
(directoryId: Id<"directories">) => `/trash/directories/${directoryId}`,
[],
)
if (!directory || !directoryContent || !rootDirectory) { if (!directory || !directoryContent || !rootDirectory) {
return <DirectoryPageSkeleton /> return <DirectoryPageSkeleton />
} }
@@ -97,7 +102,10 @@ function RouteComponent() {
value={{ rootDirectory, directory, directoryContent }} value={{ rootDirectory, directory, directoryContent }}
> >
<header className="flex py-2 shrink-0 items-center gap-2 border-b px-4 w-full"> <header className="flex py-2 shrink-0 items-center gap-2 border-b px-4 w-full">
<FilePathBreadcrumb rootLabel="Trash" /> <FilePathBreadcrumb
rootLabel="Trash"
directoryUrlFn={directoryUrlById}
/>
<div className="ml-auto flex flex-row gap-2"> <div className="ml-auto flex flex-row gap-2">
<EmptyTrashButton /> <EmptyTrashButton />
</div> </div>