From a9034fb448a6c914279539333ed80bdc6197ce26 Mon Sep 17 00:00:00 2001 From: Harshith Mullapudi Date: Wed, 11 Jun 2025 21:40:35 +0530 Subject: [PATCH] Feat: Ingest UI --- apps/webapp/app/components/api/api-table.tsx | 75 +++++++ apps/webapp/app/components/api/columns.tsx | 116 +++++++++++ apps/webapp/app/components/api/index.ts | 1 + apps/webapp/app/components/dashboard/index.ts | 1 + .../app/components/dashboard/ingest.tsx | 39 +++- .../app/components/dashboard/search.tsx | 98 ++++++++++ .../app/components/graph/graph-popover.tsx | 111 +---------- apps/webapp/app/components/graph/type.ts | 12 +- apps/webapp/app/components/graph/utils.ts | 10 +- apps/webapp/app/components/logs/index.ts | 1 + .../components/logs/ingestion-logs-table.tsx | 98 ++++++++++ .../app/components/sidebar/app-sidebar.tsx | 30 +-- .../app/components/sidebar/nav-main.tsx | 7 +- .../app/components/sidebar/nav-user.tsx | 42 ++-- apps/webapp/app/components/ui/alert.tsx | 63 ++++++ apps/webapp/app/components/ui/dialog.tsx | 132 +++++++++++++ apps/webapp/app/components/ui/pagination.tsx | 127 ++++++++++++ apps/webapp/app/components/ui/table.tsx | 125 ++++++++++++ apps/webapp/app/lib/ingest.server.ts | 22 ++- apps/webapp/app/lib/neo4j.server.ts | 10 +- .../app/routes/confirm-basic-details.tsx | 1 - apps/webapp/app/routes/home.api.tsx | 184 ++++++++++++++++++ apps/webapp/app/routes/home.dashboard.tsx | 33 +++- apps/webapp/app/routes/home.logs.tsx | 52 +++++ .../app/services/ingestionLogs.server.ts | 46 +++++ apps/webapp/app/tailwind.css | 2 +- apps/webapp/package.json | 3 + .../migration.sql | 12 ++ packages/database/prisma/schema.prisma | 9 +- pnpm-lock.yaml | 69 +++++++ 30 files changed, 1329 insertions(+), 202 deletions(-) create mode 100644 apps/webapp/app/components/api/api-table.tsx create mode 100644 apps/webapp/app/components/api/columns.tsx create mode 100644 apps/webapp/app/components/api/index.ts create mode 100644 apps/webapp/app/components/dashboard/search.tsx create mode 100644 apps/webapp/app/components/logs/index.ts create mode 100644 apps/webapp/app/components/logs/ingestion-logs-table.tsx create mode 100644 apps/webapp/app/components/ui/alert.tsx create mode 100644 apps/webapp/app/components/ui/dialog.tsx create mode 100644 apps/webapp/app/components/ui/pagination.tsx create mode 100644 apps/webapp/app/components/ui/table.tsx create mode 100644 apps/webapp/app/routes/home.api.tsx create mode 100644 apps/webapp/app/routes/home.logs.tsx create mode 100644 apps/webapp/app/services/ingestionLogs.server.ts create mode 100644 packages/database/prisma/migrations/20250611151414_add_workspace_output_to_ingestion/migration.sql 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()} /> -