diff --git a/apps/webapp/app/components/api/api-table.tsx b/apps/webapp/app/components/api/api-table.tsx new file mode 100644 index 0000000..8ca0c86 --- /dev/null +++ b/apps/webapp/app/components/api/api-table.tsx @@ -0,0 +1,75 @@ +import { + flexRender, + getCoreRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "../ui/table"; +import { type PersonalAccessToken, useTokensColumns } from "./columns"; + +export const APITable = ({ + personalAccessTokens, +}: { + personalAccessTokens: PersonalAccessToken[]; +}) => { + const columns = useTokensColumns(); + const table = useReactTable({ + data: personalAccessTokens, + columns, + getCoreRowModel: getCoreRowModel(), + }); + + return ( +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + + )} + +
+
+ ); +}; diff --git a/apps/webapp/app/components/api/columns.tsx b/apps/webapp/app/components/api/columns.tsx new file mode 100644 index 0000000..c4b8c7f --- /dev/null +++ b/apps/webapp/app/components/api/columns.tsx @@ -0,0 +1,116 @@ +import { useFetcher } from "@remix-run/react"; +import { type ColumnDef } from "@tanstack/react-table"; +import { format } from "date-fns"; +import { Button } from "../ui"; + +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "~/components/ui/dialog"; +import React from "react"; + +export interface PersonalAccessToken { + name: string; + id: string; + obfuscatedToken: string; + lastAccessedAt: Date | null; + createdAt: Date; +} + +export const useTokensColumns = (): Array> => { + const fetcher = useFetcher(); + const [open, setOpen] = React.useState(false); + + const onDelete = (id: string) => { + fetcher.submit({ id }, { method: "DELETE", action: "/home/api" }); + }; + + return [ + { + accessorKey: "name", + header: () => { + return Name; + }, + cell: ({ row }) => { + return ( +
+ {row.original.name} +
+ ); + }, + }, + { + accessorKey: "obfuscatedToken", + header: () => { + return Token; + }, + cell: ({ row }) => { + return ( +
+ {row.original.obfuscatedToken} +
+ ); + }, + }, + { + accessorKey: "lastAccessedAt", + header: () => { + return Last accessed; + }, + cell: ({ row }) => { + return ( +
+ {row.original.lastAccessedAt + ? format(row.original.lastAccessedAt, "MMM d, yyyy") + : "Never"} +
+ ); + }, + }, + { + accessorKey: "actions", + header: () => { + return Actions; + }, + cell: ({ row }) => { + return ( + + + + + + + Are you sure? + + This action cannot be undone. This will permanently delete + your API token. + + + + + + + + + ); + }, + }, + ]; +}; diff --git a/apps/webapp/app/components/api/index.ts b/apps/webapp/app/components/api/index.ts new file mode 100644 index 0000000..747cabd --- /dev/null +++ b/apps/webapp/app/components/api/index.ts @@ -0,0 +1 @@ +export * from "./api-table"; diff --git a/apps/webapp/app/components/dashboard/index.ts b/apps/webapp/app/components/dashboard/index.ts index 6e99c11..e3fea49 100644 --- a/apps/webapp/app/components/dashboard/index.ts +++ b/apps/webapp/app/components/dashboard/index.ts @@ -1 +1,2 @@ export * from "./ingest"; +export * from "./search"; diff --git a/apps/webapp/app/components/dashboard/ingest.tsx b/apps/webapp/app/components/dashboard/ingest.tsx index d2ece62..e63f884 100644 --- a/apps/webapp/app/components/dashboard/ingest.tsx +++ b/apps/webapp/app/components/dashboard/ingest.tsx @@ -1,9 +1,10 @@ -import { PlusIcon } from "lucide-react"; +import { PlusIcon, Loader2 } from "lucide-react"; import { Button } from "../ui"; import { Textarea } from "../ui/textarea"; import { useState } from "react"; import { z } from "zod"; import { EpisodeType } from "@core/types"; +import { useFetcher } from "@remix-run/react"; export const IngestBodyRequest = z.object({ episodeBody: z.string(), @@ -16,10 +17,27 @@ export const IngestBodyRequest = z.object({ export const Ingest = () => { const [text, setText] = useState(""); + const fetcher = useFetcher(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + fetcher.submit( + { + episodeBody: text, + type: "TEXT", + referenceTime: new Date().toISOString(), + source: "local", + }, + { method: "POST", action: "/home/dashboard" }, + ); + }; + + const isLoading = fetcher.state === "submitting"; return (
-
+ { value={new Date().toISOString()} /> -