diff --git a/selfie-ui/package.json b/selfie-ui/package.json index bfacf81..d1f8590 100644 --- a/selfie-ui/package.json +++ b/selfie-ui/package.json @@ -15,6 +15,7 @@ "@rjsf/utils": "^5.17.1", "@rjsf/validator-ajv8": "^5.17.1", "@tailwindcss/typography": "^0.5.10", + "@tanstack/match-sorter-utils": "^8.11.8", "@tanstack/react-table": "^8.13.2", "daisyui": "^4.6.1", "deep-chat-react": "^1.4.11", diff --git a/selfie-ui/src/app/components/Chat.tsx b/selfie-ui/src/app/components/Chat.tsx index d7f21e4..09680f6 100644 --- a/selfie-ui/src/app/components/Chat.tsx +++ b/selfie-ui/src/app/components/Chat.tsx @@ -68,19 +68,17 @@ export const Chat = ({ } }; - const auxiliaryStyle = { - scrollbar: { - width: '10px', - height: '10px', - thumb: { - backgroundColor: 'oklch(var(--n))', - borderRadius: '5px' - }, - track: { - backgroundColor: 'unset' - } - } + const auxiliaryStyle=`::-webkit-scrollbar { + width: 10px; + height: 10px; + } + ::-webkit-scrollbar-thumb { + background-color: oklch(var(--n)); + border-radius: 5px; } + ::-webkit-scrollbar-track { + background-color: unset; + }` useEffect(() => { setShowIntroPanel(!!instruction); diff --git a/selfie-ui/src/app/components/DocumentTable/DocumentTable.tsx b/selfie-ui/src/app/components/DocumentTable/DocumentTable.tsx index 6520aa9..8cdddc9 100644 --- a/selfie-ui/src/app/components/DocumentTable/DocumentTable.tsx +++ b/selfie-ui/src/app/components/DocumentTable/DocumentTable.tsx @@ -10,28 +10,20 @@ import { getFilteredRowModel, getSortedRowModel, SortingState, - useReactTable + useReactTable, + ColumnDef, } from '@tanstack/react-table'; import { rankItem } from '@tanstack/match-sorter-utils' -interface Document { - id: string; - created_at: string; - updated_at: string; - content_type: string; - name: string; - size: number; - connector_name: string; -} -const fuzzyFilter = (row, columnId, value, addMeta) => { +const fuzzyFilter = (row: any, columnId: string, value: any, addMeta: any) => { const itemRank = rankItem(row.getValue(columnId), value) addMeta({ itemRank }) return itemRank.passed } const columnHelper = createColumnHelper(); -const customColumnDefinitions = { +const customColumnDefinitions: Partial JSX.Element | string }>> = { id: { header: 'ID', }, @@ -60,12 +52,18 @@ const generateColumns = (data: Document[]) => { return columnHelper.accessor(id, { header: () => {custom?.header || id.toString().replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}, - cell: custom?.cell ? (info) => custom.cell(info.getValue()) : (info) => info.getValue(), + cell: custom?.cell ? (info) => custom?.cell?.(info.getValue()) : (info) => info.getValue(), }); }); }; -const DocumentTable = ({ data, onDeleteDocuments, onSelectionChange = (data: string[]) => {} }) => { +interface DocumentTableProps { + data: Document[]; + onDeleteDocuments: (docIds: string[]) => void; + onSelectionChange?: (selectedIds: string[]) => void; +} + +const DocumentTable: React.FC = ({ data, onDeleteDocuments, onSelectionChange = () => {} }) => { const [sorting, setSorting] = useState([]); const [selectedRows, setSelectedRows] = useState>({}); const [globalFilter, setGlobalFilter] = useState(''); @@ -73,16 +71,16 @@ const DocumentTable = ({ data, onDeleteDocuments, onSelectionChange = (data: str const allRowsSelected = data.length > 0 && data.every(({ id }) => selectedRows[id]); useEffect(() => { - setSelectedRows((prevSelectedRows) => { - const newDataIds = new Set(data.map(d => d.id)); - return Object.keys(prevSelectedRows).reduce((acc, cur) => { + const newDataIds = new Set(data.map(item => item.id)); + setSelectedRows(prevSelectedRows => { + return Object.keys(prevSelectedRows).reduce((acc: Record, cur: string) => { if (newDataIds.has(cur)) { acc[cur] = prevSelectedRows[cur]; } return acc; }, {}); }); - }, [data]); + }, [data]);; useEffect(() => { onSelectionChange(Object.keys(selectedRows).filter((id) => selectedRows[id])); @@ -92,7 +90,7 @@ const DocumentTable = ({ data, onDeleteDocuments, onSelectionChange = (data: str if (allRowsSelected) { setSelectedRows({}); } else { - const newSelectedRows = {}; + const newSelectedRows: Record = {}; data.forEach(({ id }) => { newSelectedRows[id] = true; }); @@ -137,7 +135,7 @@ const DocumentTable = ({ data, onDeleteDocuments, onSelectionChange = (data: str ), }) : null].filter(Boolean), - ], [data, selectedRows, onDeleteDocuments]); + ].filter((column): column is ColumnDef => column !== null), [data, selectedRows, onDeleteDocuments, allRowsSelected, toggleAllRowsSelected]); const table = useReactTable({ data: data ?? [], diff --git a/selfie-ui/src/app/components/DocumentTable/DocumentTableActionBar.tsx b/selfie-ui/src/app/components/DocumentTable/DocumentTableActionBar.tsx deleted file mode 100644 index d1ea30b..0000000 --- a/selfie-ui/src/app/components/DocumentTable/DocumentTableActionBar.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; - -import { Document, DocumentStats } from "@/app/types"; - -interface IndexDocumentsFormProps { - // onIndexDocuments: () => void | Promise; - // onUnindexDocuments: () => void | Promise; - indexableDocuments: Document[]; - unindexableDocuments: Document[]; - hasSelectedDocuments: boolean; - disabled?: boolean; - stats?: DocumentStats; -} - -export const DocumentTableActionBar: React.FC = ({ - // onIndexDocuments, - // onUnindexDocuments, - indexableDocuments, - unindexableDocuments, - hasSelectedDocuments, - disabled = false, - stats, - }) => { - // const handleSubmit = async (event: React.FormEvent, isIndex: boolean) => { - // event.preventDefault(); - // await (isIndex ? onIndexDocuments() : onUnindexDocuments()); - // }; - - return ( -
-
{ - }} className="flex items-center space-x-4"> - - -
- - {stats && Object.keys(stats).length && - Total: {stats.totalDocuments} | Indexed: {stats.numDocumentsIndexed} | Indexed Chunks: {stats.numEmbeddingIndexDocuments} - } -
- ); -}; diff --git a/selfie-ui/src/app/components/DocumentTable/DocumentTableRow.tsx b/selfie-ui/src/app/components/DocumentTable/DocumentTableRow.tsx deleted file mode 100644 index 19a09c9..0000000 --- a/selfie-ui/src/app/components/DocumentTable/DocumentTableRow.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, {useEffect, useState} from "react"; -import { formatDate, isDateString } from "@/app/utils"; -import { DataSource, Document } from "@/app/types"; - -interface DocumentTableRowProps { - doc: Document; - dataSource: DataSource; - columnNames: string[]; - onToggle: (docId: string) => void; - // onIndexDocument: (doc: Document) => void | Promise; - // onUnindexDocument: (doc: Document) => void | Promise; - isSelected?: boolean; - disabled?: boolean; -} - -const DocumentTableRow = React.memo(({ - doc, - dataSource, - columnNames, - onToggle, - // onIndexDocument, - // onUnindexDocument, - isSelected = false, - disabled = false, -}) => { - const [selected, setSelected] = useState(isSelected); - - useEffect(() => { - setSelected(isSelected); - }, [isSelected]); - - const handleCheckboxChange = () => { - setSelected(!selected); - onToggle(doc.id); - }; - - return ( - - - - - -
- {dataSource.name} -
- - -
- {doc.is_indexed ? '✅' : ''} -
- - {columnNames.map((colName) => ( - -
- {isDateString(doc[colName]) ? formatDate(doc[colName]) : String(doc[colName])} -
- - ))} - - {!doc.is_indexed && } - {doc.is_indexed && } - - - ); -}); - -DocumentTableRow.displayName = 'DocumentTableRow'; - -export default DocumentTableRow; diff --git a/selfie-ui/src/app/components/ManageData.tsx b/selfie-ui/src/app/components/ManageData.tsx index accf9dc..bd0a8f8 100644 --- a/selfie-ui/src/app/components/ManageData.tsx +++ b/selfie-ui/src/app/components/ManageData.tsx @@ -1,7 +1,7 @@ "use client"; import React, {useCallback, useEffect, useState} from 'react'; -import {Documents} from "@/app/types"; +import {Document} from "@/app/types"; import {apiBaseUrl} from "@/app/config"; import TaskToast from "@/app/components/TaskToast"; import useAsyncTask from "@/app/hooks/useAsyncTask"; @@ -9,7 +9,7 @@ import {DocumentTable} from "@/app/components/DocumentTable"; const ManageData = () => { - const [documents, setDocuments] = useState({}); + const [documents, setDocuments] = useState([]); const { isTaskRunning, taskMessage, executeTask } = useAsyncTask(); @@ -22,7 +22,7 @@ const ManageData = () => { success: 'Documents loaded', error: 'Failed to load documents', }); - }, [executeTask, apiBaseUrl]); + }, [executeTask]); useEffect(() => { fetchDocuments(); @@ -62,7 +62,7 @@ const ManageData = () => { ].join(' ')}> diff --git a/selfie-ui/src/app/types/index.ts b/selfie-ui/src/app/types/index.ts index c92fd36..44d54ae 100644 --- a/selfie-ui/src/app/types/index.ts +++ b/selfie-ui/src/app/types/index.ts @@ -1,13 +1,14 @@ // TODO: define this type -export type Document = any -// export interface Document { -// id: string -// metadata: { -// [key: string]: any -// } -// is_indexed: boolean -// num_index_documents?: number -// } + +export interface Document { + id: string; + created_at: string; + updated_at: string; + content_type: string; + name: string; + size: number; + connector_name: string; +} export interface Documents { [sourceId: string]: Document[] diff --git a/selfie-ui/yarn.lock b/selfie-ui/yarn.lock index 45ba7ce..4e1296b 100644 --- a/selfie-ui/yarn.lock +++ b/selfie-ui/yarn.lock @@ -271,6 +271,13 @@ lodash.merge "^4.6.2" postcss-selector-parser "6.0.10" +"@tanstack/match-sorter-utils@^8.11.8": + version "8.11.8" + resolved "https://registry.yarnpkg.com/@tanstack/match-sorter-utils/-/match-sorter-utils-8.11.8.tgz#9132c2a21cf18ca2f0071b604ddadb7a66e73367" + integrity sha512-3VPh0SYMGCa5dWQEqNab87UpCMk+ANWHDP4ALs5PeEW9EpfTAbrezzaOk/OiM52IESViefkoAOYuxdoa04p6aA== + dependencies: + remove-accents "0.4.2" + "@tanstack/react-table@^8.13.2": version "8.13.2" resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.13.2.tgz#a3aa737ae464abc651f68daa7e82dca17813606c" @@ -3011,6 +3018,11 @@ remarkable@^2.0.1: argparse "^1.0.10" autolinker "^3.11.0" +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== + require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"