UNPKG

@llamaindex/ui

Version:

A comprehensive UI component library built with React, TypeScript, and Tailwind CSS for LlamaIndex applications

594 lines (589 loc) 23 kB
'use strict'; var chunkZWURW2XT_js = require('./chunk-ZWURW2XT.js'); var chunkMAZG242C_js = require('./chunk-MAZG242C.js'); var chunk7FAJFTEY_js = require('./chunk-7FAJFTEY.js'); var chunkKRF4WMPE_js = require('./chunk-KRF4WMPE.js'); var chunkKQINV2AN_js = require('./chunk-KQINV2AN.js'); var chunkGSVP3T3X_js = require('./chunk-GSVP3T3X.js'); var chunkNO3TBBOW_js = require('./chunk-NO3TBBOW.js'); var chunk6WYFXTHF_js = require('./chunk-6WYFXTHF.js'); var chunk64FRNQ3S_js = require('./chunk-64FRNQ3S.js'); var chunkHK7TFVDA_js = require('./chunk-HK7TFVDA.js'); var chunkORMEWXMH_js = require('./chunk-ORMEWXMH.js'); var react = require('react'); var lucideReact = require('lucide-react'); var jsxRuntime = require('react/jsx-runtime'); var sonner = require('sonner'); function useItemGridData(paginationState, filterFields = {}, sortSpec = void 0) { const client = chunk6WYFXTHF_js.useAgentDataClient(); const [data, setData] = react.useState([]); const [loading, setLoading] = react.useState(true); const [error, setError] = react.useState(null); const [totalSize, setTotalSize] = react.useState(0); const fetchData = react.useCallback(async () => { setLoading(true); setError(null); try { const response = await client.search({ filter: filterFields, orderBy: sortSpec, offset: paginationState.page * paginationState.size, pageSize: paginationState.size, includeTotal: true }); setData(response.items || []); setTotalSize(response.totalSize || 0); } catch (err) { setError(err instanceof Error ? err.message : "An error occurred"); } finally { setLoading(false); } }, [ paginationState.page, paginationState.size, JSON.stringify(filterFields), sortSpec, client ]); const handleDeleteItem = react.useCallback( async (itemId) => { try { await client.deleteItem(itemId); setData( (prevData) => prevData.filter((item) => String(item.id) !== String(itemId)) ); setTotalSize((prevTotal) => prevTotal - 1); return { success: true }; } catch (error2) { console.error("Delete error:", error2); return { success: false, error: "Failed to delete item. Please try again." }; } }, [client] ); react.useEffect(() => { fetchData(); }, [fetchData]); return { data, loading, error, totalSize, deleteItem: handleDeleteItem, fetchData }; } function ColumnHeader({ column, sortState, onSort, filterOptions, selectedFilters, onFilterChange }) { var _a; const sortKey = (_a = column.sortKey) != null ? _a : column.key; const sortDirection = (sortState == null ? void 0 : sortState.column) === sortKey ? sortState.direction : null; return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [ /* @__PURE__ */ jsxRuntime.jsxs( "div", { className: chunkHK7TFVDA_js.cn( "flex items-center justify-center space-x-1", column.sortable && "cursor-pointer hover:text-primary" ), onClick: () => column.sortable && (onSort == null ? void 0 : onSort(sortKey)), children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base-muted-foreground text-sm font-medium", children: column.header }), column.sortable && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col", children: sortDirection === "asc" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { size: 16 }) : sortDirection === "desc" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { size: 16 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpDown, { size: 16, className: "opacity-40" }) }) ] } ), filterOptions && filterOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx( chunk7FAJFTEY_js.ColumnFilter, { options: filterOptions, selectedValues: selectedFilters || [], onFilterChange: (values) => onFilterChange == null ? void 0 : onFilterChange(column.key, values) } ) ] }); } var PAGE_SIZE_OPTIONS = [10, 20, 50, 100]; function PaginationControls({ paginationState, totalSize, onPaginationChange }) { const { page, size } = paginationState; const totalPages = Math.max(1, Math.ceil(totalSize / size)); function getPageNumbers() { if (totalPages <= 5) return Array.from({ length: totalPages }, (_, i) => i); if (page <= 2) return [0, 1, 2, -1, totalPages - 1]; if (page >= totalPages - 3) return [0, -1, totalPages - 3, totalPages - 2, totalPages - 1]; return [0, -1, page, -1, totalPages - 1]; } return /* @__PURE__ */ jsxRuntime.jsx(chunkKQINV2AN_js.Pagination, { children: /* @__PURE__ */ jsxRuntime.jsxs(chunkKQINV2AN_js.PaginationContent, { className: "flex w-full items-center justify-between", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-base-foreground", children: "Rows per page" }), /* @__PURE__ */ jsxRuntime.jsxs(chunkKRF4WMPE_js.DropdownMenu, { children: [ /* @__PURE__ */ jsxRuntime.jsx(chunkKRF4WMPE_js.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "border rounded px-2 py-1 text-sm min-w-[48px] text-left focus:outline-none cursor-pointer", children: size }) }), /* @__PURE__ */ jsxRuntime.jsx(chunkKRF4WMPE_js.DropdownMenuContent, { align: "start", children: PAGE_SIZE_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsx( chunkKRF4WMPE_js.DropdownMenuItem, { onClick: () => onPaginationChange({ page: 0, size: option }), className: chunkHK7TFVDA_js.cn( "cursor-pointer px-2 py-1 text-sm", size === option && "bg-accent font-bold text-primary" ), children: option }, option )) }) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [ /* @__PURE__ */ jsxRuntime.jsx(chunkKQINV2AN_js.PaginationItem, { children: /* @__PURE__ */ jsxRuntime.jsx( chunkKQINV2AN_js.PaginationPrevious, { onClick: () => page > 0 && onPaginationChange(chunkORMEWXMH_js.__spreadProps(chunkORMEWXMH_js.__spreadValues({}, paginationState), { page: page - 1 })), className: chunkHK7TFVDA_js.cn( page === 0 && "pointer-events-none opacity-50", "text-base-foreground", "cursor-pointer" ) } ) }), getPageNumbers().map( (num, idx) => num === -1 ? /* @__PURE__ */ jsxRuntime.jsx(chunkKQINV2AN_js.PaginationItem, { children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 text-base-foreground text-xs", children: "..." }) }, "ellipsis-" + idx) : /* @__PURE__ */ jsxRuntime.jsx(chunkKQINV2AN_js.PaginationItem, { children: /* @__PURE__ */ jsxRuntime.jsx( chunkKQINV2AN_js.PaginationLink, { isActive: page === num, onClick: () => onPaginationChange(chunkORMEWXMH_js.__spreadProps(chunkORMEWXMH_js.__spreadValues({}, paginationState), { page: num })), className: chunkHK7TFVDA_js.cn( "text-base-foreground", "size-7", "cursor-pointer" ), children: num + 1 } ) }, num) ), /* @__PURE__ */ jsxRuntime.jsx(chunkKQINV2AN_js.PaginationItem, { children: /* @__PURE__ */ jsxRuntime.jsx( chunkKQINV2AN_js.PaginationNext, { onClick: () => page < totalPages - 1 && onPaginationChange(chunkORMEWXMH_js.__spreadProps(chunkORMEWXMH_js.__spreadValues({}, paginationState), { page: page + 1 })), className: chunkHK7TFVDA_js.cn( page >= totalPages - 1 && "pointer-events-none opacity-50", "text-base-foreground", "cursor-pointer" ) } ) }) ] }) ] }) }); } function ItemGrid({ customColumns = [], onRowClick, defaultPageSize = 20 }) { const [paginationState, setPaginationState] = react.useState({ page: 0, size: defaultPageSize }); const [sortState, setSortState] = react.useState({ column: "created_at", direction: "desc" }); const [filters, setFilters] = react.useState({}); const columns = react.useMemo(() => { const finalColumns = []; finalColumns.push(...customColumns); return finalColumns; }, [customColumns]); const apiFilters = react.useMemo(() => { const result = {}; Object.entries(filters).forEach(([columnKey, filterValues]) => { if (filterValues.length > 0) { result[columnKey] = { includes: filterValues }; } }); return result; }, [filters]); const apiSort = react.useMemo(() => { let result = void 0; if (sortState.column && sortState.direction) { result = `${sortState.column} ${sortState.direction}`; } return result; }, [sortState]); const { data, loading, error, totalSize, deleteItem, fetchData } = useItemGridData(paginationState, apiFilters, apiSort); const hooks = react.useMemo( () => ({ deleteItem, fetchData }), [deleteItem, fetchData] ); const handleSort = (columnKey) => { setSortState((prev) => { if (prev.column === columnKey) { const newDirection = prev.direction === "asc" ? "desc" : prev.direction === "desc" ? null : "asc"; return { column: columnKey, direction: newDirection }; } else { return { column: columnKey, direction: "asc" }; } }); }; const handleFilterChange = (columnKey, values) => { setFilters((prev) => chunkORMEWXMH_js.__spreadProps(chunkORMEWXMH_js.__spreadValues({}, prev), { [columnKey]: values })); }; const getFilterOptions = (columnKey) => { const column = columns.find((col) => col.key === columnKey); if (!column || !column.filterable) return []; if (column.filterOptions) { return column.filterOptions; } const values = data.map((item) => { const value = column.getValue(item); return String(value || ""); }).filter(Boolean); return [...new Set(values)].sort(); }; if (loading) { return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center items-center p-8", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", children: "Loading items..." }) }); } if (error) { return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-destructive/50 bg-destructive/10 p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-destructive", children: [ "Error loading items: ", error ] }) }); } return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full space-y-4", children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxRuntime.jsxs(chunkNO3TBBOW_js.Table, { className: "table-fixed", children: [ /* @__PURE__ */ jsxRuntime.jsx(chunkNO3TBBOW_js.TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(chunkNO3TBBOW_js.TableRow, { children: columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx( chunkNO3TBBOW_js.TableHead, { className: chunkHK7TFVDA_js.cn( "font-medium", column.key === "actions" && "w-15" ), children: /* @__PURE__ */ jsxRuntime.jsx( ColumnHeader, { column, sortState, onSort: handleSort, filterOptions: getFilterOptions(column.key), selectedFilters: filters[column.key], onFilterChange: handleFilterChange } ) }, column.key )) }) }), /* @__PURE__ */ jsxRuntime.jsx(chunkNO3TBBOW_js.TableBody, { children: data.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx(chunkNO3TBBOW_js.TableRow, { className: "sr-only", children: columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx( chunkNO3TBBOW_js.TableCell, { className: column.key === "actions" ? "w-15" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-0 overflow-hidden", children: "placeholder" }) }, column.key )) }), /* @__PURE__ */ jsxRuntime.jsx(chunkNO3TBBOW_js.TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx( chunkNO3TBBOW_js.TableCell, { colSpan: columns.length, className: "h-24 text-center text-muted-foreground", children: "No items found." } ) }) ] }) : data.map((item, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx( chunkNO3TBBOW_js.TableRow, { className: chunkHK7TFVDA_js.cn( "transition-colors hover:bg-muted/50", onRowClick && "cursor-pointer" ), onClick: () => onRowClick == null ? void 0 : onRowClick(item), children: columns.map((column) => { const value = column.getValue(item); return /* @__PURE__ */ jsxRuntime.jsx( chunkNO3TBBOW_js.TableCell, { className: column.key === "actions" ? "w-15" : void 0, children: column.renderCell ? column.renderCell(value, hooks) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base-foreground text-sm font-normal leading-none", children: String(value || "-") }) }, column.key ); }) }, item.id || rowIndex )) }) ] }) }), /* @__PURE__ */ jsxRuntime.jsx( PaginationControls, { paginationState, totalSize, onPaginationChange: setPaginationState } ) ] }); } function ReviewStatusBadge({ value }) { const statusConfig = { pending_review: { label: "Awaiting Review", variant: "secondary", className: "bg-amber-100 text-amber-600 hover:bg-amber-200" }, approved: { label: "Approved", variant: "default", className: "bg-green-100 text-green-600 hover:bg-green-200" }, rejected: { label: "Rejected", variant: "destructive", className: "bg-red-100 text-red-600 hover:bg-red-200" } }; const config = statusConfig[value] || { label: value, variant: "outline", className: "" }; return /* @__PURE__ */ jsxRuntime.jsx(chunkZWURW2XT_js.Badge, { variant: config.variant, className: config.className, children: config.label }); } function SyncedIcon({ value }) { return value ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "w-4 h-4 text-green-600" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "w-4 h-4 text-red-600" }); } function FormattedDate({ value }) { const time = react.useMemo(() => { const date = new Date(value); return date.toLocaleString(); }, [value]); return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base-foreground text-sm font-normal leading-none", children: time }); } function ActionButton({ onDelete }) { const [showDeleteDialog, setShowDeleteDialog] = react.useState(false); return /* @__PURE__ */ jsxRuntime.jsxs("div", { onClick: (e) => e.stopPropagation(), children: [ /* @__PURE__ */ jsxRuntime.jsxs(chunkKRF4WMPE_js.DropdownMenu, { children: [ /* @__PURE__ */ jsxRuntime.jsx(chunkKRF4WMPE_js.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx( chunk64FRNQ3S_js.Button, { variant: "ghost", size: "sm", className: "h-8 w-8 p-0 cursor-pointer", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVerticalIcon, { className: "w-4 h-4" }) } ) }), /* @__PURE__ */ jsxRuntime.jsx(chunkKRF4WMPE_js.DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs( chunkKRF4WMPE_js.DropdownMenuItem, { onClick: (e) => { e.stopPropagation(); setShowDeleteDialog(true); }, className: "text-destructive focus:text-destructive", children: [ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrashIcon, { className: "w-4 h-4 mr-2" }), "Delete" ] } ) }) ] }), /* @__PURE__ */ jsxRuntime.jsx(chunkMAZG242C_js.AlertDialog, { open: showDeleteDialog, onOpenChange: setShowDeleteDialog, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkMAZG242C_js.AlertDialogContent, { children: [ /* @__PURE__ */ jsxRuntime.jsxs(chunkMAZG242C_js.AlertDialogHeader, { children: [ /* @__PURE__ */ jsxRuntime.jsx(chunkMAZG242C_js.AlertDialogTitle, { children: "Delete Item" }), /* @__PURE__ */ jsxRuntime.jsx(chunkMAZG242C_js.AlertDialogDescription, { children: "Are you sure you want to delete this item? This action cannot be undone." }) ] }), /* @__PURE__ */ jsxRuntime.jsxs(chunkMAZG242C_js.AlertDialogFooter, { children: [ /* @__PURE__ */ jsxRuntime.jsx(chunkMAZG242C_js.AlertDialogCancel, { className: "cursor-pointer", children: "Cancel" }), /* @__PURE__ */ jsxRuntime.jsx( chunkMAZG242C_js.AlertDialogAction, { onClick: () => { onDelete(); setShowDeleteDialog(false); }, className: "bg-red-600 text-white hover:bg-red-700 focus:ring-2 focus:ring-red-500 focus:ring-offset-2 cursor-pointer font-medium transition-colors", children: "Delete" } ) ] }) ] }) }) ] }); } // src/item-grid/built-in-columns.tsx var STATUS_OPTIONS = [ { value: "pending_review", label: "In Review" }, { value: "approved", label: "Accepted" }, { value: "rejected", label: "Rejected" } ]; var EXTRACTED_DATA_COLUMN_NAMES = [ "fileName", "status", "itemsToReview", "createdAt", "actions" ]; function getExtractedDataItemsToReviewCount(item, confidenceThreshold = chunkGSVP3T3X_js.DEFAULT_CONFIDENCE_THRESHOLD) { const metadata = item.data.field_metadata; if (!metadata || typeof metadata !== "object") return 0; let lowConfidenceCount = 0; const visit = (node) => { if (!node || typeof node !== "object") return; if (Array.isArray(node)) { node.forEach(visit); return; } const obj = node; const confidence = obj.confidence; const hasNestedObjectChild = Object.values(obj).some( (v) => v && typeof v === "object" && !Array.isArray(v) ); if (typeof confidence === "number" && !hasNestedObjectChild) { if (confidence < confidenceThreshold) lowConfidenceCount++; return; } Object.values(obj).forEach(visit); }; visit(metadata); return lowConfidenceCount; } function createExtractedDataColumn(columnName, config, confidenceThreshold = chunkGSVP3T3X_js.DEFAULT_CONFIDENCE_THRESHOLD) { let baseColumn; switch (columnName) { case "fileName": baseColumn = { key: "file_name", header: "File Name", getValue: (item) => item.data.file_name, sortable: true }; break; case "status": baseColumn = { key: "status", header: "Status", getValue: (item) => item.data.status, renderCell: (value) => /* @__PURE__ */ jsxRuntime.jsx(ReviewStatusBadge, { value }), filterable: true, filterOptions: STATUS_OPTIONS.map((option) => option.value), sortable: true }; break; case "itemsToReview": baseColumn = { key: "items_to_review", header: "Items to Review", getValue: (item) => getExtractedDataItemsToReviewCount(item, confidenceThreshold), renderCell: (value) => { const count = value; return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base-foreground text-xs font-normal leading-none", children: count }); }, sortable: false }; break; case "createdAt": baseColumn = { key: "created_at", header: "Created At", getValue: (item) => item.createdAt.toISOString(), renderCell: (value) => /* @__PURE__ */ jsxRuntime.jsx(FormattedDate, { value }), sortable: true }; break; case "actions": baseColumn = { key: "actions", header: "", getValue: (item) => item, renderCell: (value, hooks) => { if (!(hooks == null ? void 0 : hooks.deleteItem)) { return null; } const item = value; const deleteItem = hooks.deleteItem; return /* @__PURE__ */ jsxRuntime.jsx( ActionButton, { onDelete: async () => { const result = await deleteItem(item.id); if (!result.success && result.error) { sonner.toast.error(result.error); } } } ); } }; break; } if (!baseColumn) { throw new Error(`Unknown extracted-data column: ${columnName}`); } if (config === false) { throw new Error(`Column ${columnName} is disabled`); } if (config === true) { return baseColumn; } return chunkORMEWXMH_js.__spreadValues(chunkORMEWXMH_js.__spreadValues({}, baseColumn), config); } function ExtractedDataItemGrid({ customColumns = [], builtInColumns = {}, onRowClick, defaultPageSize = 20 }) { const confidenceThreshold = chunkGSVP3T3X_js.useUIConfigStore( (state) => state.confidenceThreshold ); const columns = []; columns.push(...customColumns); EXTRACTED_DATA_COLUMN_NAMES.forEach((name) => { const config = builtInColumns[name]; if (config !== false && config !== void 0) { try { const builtInColumn = createExtractedDataColumn( name, config, confidenceThreshold ); columns.push(builtInColumn); } catch (e) { } } }); return /* @__PURE__ */ jsxRuntime.jsx( ItemGrid, { customColumns: columns, onRowClick, defaultPageSize } ); } exports.ColumnHeader = ColumnHeader; exports.EXTRACTED_DATA_COLUMN_NAMES = EXTRACTED_DATA_COLUMN_NAMES; exports.ExtractedDataItemGrid = ExtractedDataItemGrid; exports.FormattedDate = FormattedDate; exports.ItemGrid = ItemGrid; exports.PaginationControls = PaginationControls; exports.ReviewStatusBadge = ReviewStatusBadge; exports.STATUS_OPTIONS = STATUS_OPTIONS; exports.SyncedIcon = SyncedIcon; exports.createExtractedDataColumn = createExtractedDataColumn; exports.getExtractedDataItemsToReviewCount = getExtractedDataItemsToReviewCount; exports.useItemGridData = useItemGridData;