Skip to content

Commit

Permalink
folder navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
slayernominee committed Jan 6, 2024
1 parent 915c8e8 commit 5a5c07c
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 23 deletions.
29 changes: 28 additions & 1 deletion app/dashboard/files/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,37 @@ export const columns: ColumnDef<File>[] = [
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Modified
Modified x ago
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
)
},
cell: ({ row }) => {
const modified = parseFloat(row.getValue("modified"))

let formatted: number | string = 0

if (modified > 365 * 24 * 60 * 60 * 1000) { // 365d
formatted = Math.round(modified / 1000 / 60 / 60 / 24 / 365)
formatted = `${formatted}y`
} else if (modified > 7 * 24 * 60 * 60 * 1000) { // 365d
formatted = Math.round(modified / 1000 / 60 / 60 / 24 / 7)
formatted = `${formatted}w`
} else if (modified > 24 * 60 * 60 * 1000) { // 24h
formatted = Math.round(modified / 1000 / 60 / 60 / 24)
formatted = `${formatted}d`
} else if (modified > 60 * 60 * 1000) { // 60min
formatted = Math.round(modified / 1000 / 60 / 60)
formatted = `${formatted}h`
} else if (modified > 60 * 1000) { // 60s
formatted = Math.round(modified / 1000 / 60)
formatted = `${formatted}m`
} else {
formatted = Math.round(modified / 1000)
formatted = `${formatted}s`
}

return <div className="text-right font-medium">{formatted} ago</div>
},
},
]
22 changes: 21 additions & 1 deletion app/dashboard/files/data-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,32 @@ import {
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[]
cellClick: any
}

export function DataTable<TData, TValue>({
columns,
data,
cellClick,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [rowSelection, setRowSelection] = React.useState({})

const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
onRowSelectionChange: setRowSelection,
state: {
sorting,
rowSelection,
},
})

return (
<div>
<div className="rounded-md border">
<Table>
<TableHeader>
Expand Down Expand Up @@ -69,7 +76,7 @@ export function DataTable<TData, TValue>({
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
<TableCell key={cell.id} onClick={() => {cellClick(cell)}}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
Expand All @@ -85,5 +92,18 @@ export function DataTable<TData, TValue>({
</TableBody>
</Table>
</div>



<div className="flex items-center justify-end space-x-2 py-4">

<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>

</div>

</div>
)
}
69 changes: 54 additions & 15 deletions app/dashboard/files/page.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
"use client"
import { Layout } from "@/app/components/dash_lay"
import React, { useRef, useEffect, useState } from 'react';
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { Checkbox } from "@/components/ui/checkbox"
import { Button } from "@/components/ui/button"
import Icon from '@mdi/react';
import { mdiDeleteOutline, mdiFolderMoveOutline, mdiPencilOutline } from '@mdi/js';
import { mdiDeleteOutline, mdiChevronLeft, mdiFolderMoveOutline, mdiHomeOutline, mdiPencilOutline, mdiReload, mdiCloudDownloadOutline, mdiCloudUploadOutline, mdiContentCopy } from '@mdi/js';

import { File, columns } from "@/app/dashboard/files/columns"
import { DataTable } from "@/app/dashboard/files/data-table"


async function getData(): Promise<File[]> {
const res = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/files/&.', {
async function getData(path: string): Promise<File[]> {
const res = await fetch(process.env.NEXT_PUBLIC_API_URL + '/api/files/' + path, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token'),
Expand All @@ -39,17 +29,66 @@ async function getData(): Promise<File[]> {

export default function Home() {
const [data, setData] = useState<File[]>([])
const [path, setPath] = useState("&.")

const refresh = async () => {
const res = await getData(path)
setData(res)
}

useEffect(() => {
getData().then(res => setData(res))
getData(path).then(res => setData(res))
}, [])


const goToHome = async () => {
setPath("&.")
const res = await getData("&.")
setData(res)
}

const goUpwards = async () => {
const pathArr = path.split("&")
pathArr.pop()
const newPath = pathArr.join("&")
setPath(newPath)
const res = await getData(newPath)
setData(res)
}

const handleClick = async (cell: any) => {

if (cell.getContext().row.original.is_dir) {
// go in the directory
setPath(path + "&" + cell.getContext().row.original.name)
const res = await getData(path + "&" + cell.getContext().row.original.name)
setData(res)
} else {
// open the file? or download it?
}

}

return (
<Layout>
<h1>Files</h1>

<DataTable columns={columns} data={data} />
{ path }

<div>
<Button variant="secondary" disabled={path == '&.'} onClick={goToHome}><Icon path={mdiHomeOutline} size={1} /></Button>
<Button variant="secondary" disabled={path == '&.'} onClick={goUpwards}><Icon path={mdiChevronLeft} size={1} /></Button>

<Button variant="secondary"><Icon path={mdiCloudDownloadOutline} size={1} /></Button>
<Button variant="secondary"><Icon path={mdiCloudUploadOutline} size={1} /></Button>
<Button variant="secondary"><Icon path={mdiPencilOutline} size={1} /></Button>
<Button variant="secondary"><Icon path={mdiFolderMoveOutline} size={1} /></Button>
<Button variant="secondary"><Icon path={mdiContentCopy} size={1} /></Button>
<Button variant="secondary"><Icon path={mdiDeleteOutline} size={1} /></Button>
<Button variant="secondary" onClick={refresh}><Icon path={mdiReload} size={1} /></Button>
</div>

<DataTable cellClick={handleClick} columns={columns} data={data} />

</Layout>
)
Expand Down
15 changes: 9 additions & 6 deletions dash/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ struct FileInfo {
pub async fn get_files(path: web::Path<String>) -> Result<impl Responder> {
let mut pathname = path.into_inner();

if pathname.contains("..") {
/*if pathname.contains("..") || pathname.contains("~") || pathname.starts_with("-") || pathname.contains("//") || pathname.contains("\\") || pathname.contains(":") || pathname.contains("*") || pathname.contains("?") || pathname.contains("\"") || pathname.contains("<") || pathname.contains(">") || pathname.contains("|") {
return Ok(HttpResponse::BadRequest().body("Invalid Pathname!"));
}

if pathname == "&." {
pathname = ".".to_string();
}
}*/
// theoretically but since this only works with tokens the user can be trusted ...


pathname = pathname.replace("&.", ".");
pathname = pathname.replace("&", "/");

println!("Pathname: {}", pathname);

let path = Path::new(&pathname);

Expand Down

0 comments on commit 5a5c07c

Please sign in to comment.