Skip to content

Commit

Permalink
feat: add import/index documents ui (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mini256 authored May 14, 2024
1 parent 6ac0c8d commit 6635edf
Show file tree
Hide file tree
Showing 31 changed files with 800 additions and 212 deletions.
2 changes: 1 addition & 1 deletion src/app/(main)/(admin)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function IndexStats ({}: {}) {
<div>
{data?.chunks ?? '--'} chunks
</div>
<Link href="/explore" className="text-xs flex items-center gap-1 transition-colors text-muted-foreground hover:text-foreground">
<Link href="/documents" className="text-xs flex items-center gap-1 transition-colors text-muted-foreground hover:text-foreground">
Explore <ArrowRightIcon size="1em" />
</Link>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {DataTableRowActions} from "@/app/(main)/(admin)/explore/components/data-table-row-actions";
import {DataTableColumnHeader} from "@/app/(main)/(admin)/documents/components/data-table-column-header";
import {DataTableRowActions} from "@/app/(main)/(admin)/documents/components/data-table-row-actions";
import {Tooltip, TooltipContent, TooltipTrigger} from "@/components/ui/tooltip";
import type {Document} from "@/core/repositories/document";
import type {CellContext, ColumnDef} from "@tanstack/react-table";
Expand All @@ -15,14 +16,27 @@ const datetime = (cell: CellContext<any, any>) => <time>{format(cell.getValue(),
const GITHUB_PAGE_URL_REGEXP = /^https?:\/\/github\.com\/([^\/]+)\/([^\/]+)(?:\/blob\/([^/]+))?/;

export const columns = [
helper.accessor('id', {cell: mono}),
helper.accessor('id', {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="id" />
),
cell: mono,
enableSorting: true,
}),
helper.accessor('name', {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="name" />
),
cell: (cell: CellContext<any, any>) => <div className="flex space-x-2">
<span className="max-w-[500px] truncate font-medium">{cell.getValue()}</span>
</div>,
enableSorting: true
}),
helper.accessor('mime', {cell: mono}),
helper.accessor('source_uri', {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="source_uri" />
),
cell: (cell: CellContext<any, any>) => {
const value = cell.getValue();

Expand Down Expand Up @@ -50,7 +64,8 @@ export const columns = [
return <div className="flex space-x-2">
<span className="max-w-[300px] truncate font-medium">{cell.getValue()}</span>
</div>;
}
},
enableSorting: true
}),
helper.accessor('hash', {
cell: (cell: CellContext<any, any>) => <span className="font-mono">
Expand All @@ -62,10 +77,19 @@ export const columns = [
</span>
}),
helper.accessor('created_at', {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="created_at" />
),
cell: datetime,
enableSorting: true
}),
helper.accessor('last_modified_at', {cell: datetime}),
helper.accessor('last_modified_at', {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="last_modified_at" />
),
cell: datetime,
enableSorting: true,
}),
{
id: "actions",
cell: ({ row }) => <DataTableRowActions row={row} />,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
ArrowDownIcon,
ArrowUpIcon,
CaretSortIcon,
EyeNoneIcon,
} from "@radix-ui/react-icons"
import { Column } from "@tanstack/react-table"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"

interface DataTableColumnHeaderProps<TData, TValue>
extends React.HTMLAttributes<HTMLDivElement> {
column: Column<TData, TValue>
title: string
}

export function DataTableColumnHeader<TData, TValue>({
column,
title,
className,
}: DataTableColumnHeaderProps<TData, TValue>) {
if (!column.getCanSort()) {
return <div className={cn(className)}>{title}</div>
}

return (
<div className={cn("flex items-center space-x-2", className)}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="sm"
className="-ml-3 h-8 data-[state=open]:bg-accent"
>
<span>{title}</span>
{column.getIsSorted() === "desc" ? (
<ArrowDownIcon className="ml-2 h-4 w-4" />
) : column.getIsSorted() === "asc" ? (
<ArrowUpIcon className="ml-2 h-4 w-4" />
) : (
<CaretSortIcon className="ml-2 h-4 w-4" />
)}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem onClick={() => column.toggleSorting(false)}>
<ArrowUpIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
Asc
</DropdownMenuItem>
<DropdownMenuItem onClick={() => column.toggleSorting(true)}>
<ArrowDownIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
Desc
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
<EyeNoneIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
Hide
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use client"

import {BuildDocumentIndexDialog} from "@/app/(main)/(admin)/documents/components/dialogs/build-document-index-dialog";
import type {Document} from "@/core/repositories/document";
import { DotsHorizontalIcon } from "@radix-ui/react-icons"
import { Row } from "@tanstack/react-table"

import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {useState} from "react";


interface DataTableRowActionsProps {
row: Row<Document>
}

export function DataTableRowActions<TData>(props: DataTableRowActionsProps) {
const [dialogOpen, setDialogOpen] = useState(false);

return (
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="flex h-8 w-8 p-0 data-[state=open]:bg-muted"
>
<DotsHorizontalIcon className="h-4 w-4" />
<span className="sr-only">Open menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[160px]">
<DropdownMenuItem onSelect={() => setDialogOpen(true)}>Build Index</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem disabled={true}>
Delete
<DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<BuildDocumentIndexDialog
documentRows={[props.row]}
trigger={null}
open={dialogOpen}
handleOpenChange={setDialogOpen}
/>
</>
)
}
73 changes: 73 additions & 0 deletions src/app/(main)/(admin)/documents/components/data-table-toolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"use client"

import {DataTableViewOptions} from "@/app/(main)/(admin)/documents/components/data-table-view-options";
import {ImportDocumentsDialog} from "@/app/(main)/(admin)/documents/components/dialogs/import-documents-dialog";
import {BuildDocumentIndexDialog} from "@/app/(main)/(admin)/documents/components/dialogs/build-document-index-dialog";
import { Cross2Icon } from "@radix-ui/react-icons"
import {Row, Table} from "@tanstack/react-table"
import type {Document} from "@/core/repositories/document";

import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {useState} from "react";

interface DataTableToolbarProps {
table: Table<Document>
}

const documentMap = new Map<string, Row<Document>>();

export function DataTableToolbar({ table }: DataTableToolbarProps) {
const isFiltered = table.getState().columnFilters.length > 0;
const selectedRowIds = Object.keys(table.getState().rowSelection);
const nSelectedRows = selectedRowIds.length;
const isSelected = nSelectedRows > 0;

const documentRows = table.getSelectedRowModel().rows;
for (let documentRow of documentRows) {
documentMap.set(documentRow.id, documentRow)
}

const [dialogOpen, setDialogOpen] = useState(false);

return (
<div className="flex items-center justify-between">
<div className="flex flex-1 items-center space-x-2">
<Input
placeholder="Filter documents..."
value={(table.getColumn("name")?.getFilterValue() as string) ?? ""}
onChange={(event: { target: { value: any } }) =>
table.getColumn("name")?.setFilterValue(event.target.value)
}
className="h-8 w-[150px] lg:w-[250px]"
/>
{isFiltered && (
<Button
variant="ghost"
onClick={() => table.resetColumnFilters()}
className="h-8 px-2 lg:px-3"
>
Reset
<Cross2Icon className="ml-2 h-4 w-4" />
</Button>
)}
</div>
<div className="flex flex-1 items-center space-x-2">
<DataTableViewOptions table={table} />
<ImportDocumentsDialog trigger={<Button size="sm">Import documents</Button>}/>
{
isSelected && (
<BuildDocumentIndexDialog
documentRows={selectedRowIds.map(id => documentMap.get(id) as Row<Document>)}
open={dialogOpen}
handleOpenChange={setDialogOpen}
trigger={
<Button size="sm">Build Indexes ({nSelectedRows})</Button>
}
/>
)
}
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client"

import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu"
import { MixerHorizontalIcon } from "@radix-ui/react-icons"
import { Table } from "@tanstack/react-table"

import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu"

interface DataTableViewOptionsProps<TData> {
table: Table<TData>
}

export function DataTableViewOptions<TData>({
table,
}: DataTableViewOptionsProps<TData>) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className="ml-auto hidden h-8 lg:flex"
>
<MixerHorizontalIcon className="mr-2 h-4 w-4" />
View
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[150px]">
<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
<DropdownMenuSeparator />
{table
.getAllColumns()
.filter(
(column) =>
typeof column.accessorFn !== "undefined" && column.getCanHide()
)
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) => column.toggleVisibility(!!value)}
>
{column.id}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
)
}
Loading

0 comments on commit 6635edf

Please sign in to comment.