Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions qtype/interpreter/conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
from llama_index.core.memory import Memory as LlamaMemory
from llama_index.core.schema import Document as LlamaDocument
from llama_index.core.vector_stores.types import BasePydanticVectorStore
from opensearchpy import AsyncOpenSearch, AWSV4SignerAuth
from opensearchpy import AsyncHttpConnection, AsyncOpenSearch
from opensearchpy.helpers.asyncsigner import AWSV4SignerAsyncAuth

from qtype.base.types import PrimitiveTypeEnum
from qtype.dsl.domain_types import (
Expand Down Expand Up @@ -369,7 +370,7 @@ def to_opensearch_client(
InterpreterError: If authentication fails or configuration is invalid
"""
client_kwargs: dict[str, Any] = {
"hosts": [index.endpoint],
"hosts": index.endpoint,
**index.args,
}

Expand All @@ -390,15 +391,17 @@ def to_opensearch_client(
f"Failed to obtain AWS credentials for DocumentIndex '{index.id}'"
)

# Use opensearch-py's built-in AWS auth
aws_auth = AWSV4SignerAuth(
# Use opensearch-py's async AWS auth
aws_auth = AWSV4SignerAsyncAuth(
credentials,
auth_session.region_name or "us-east-1", # type: ignore
"aoss", # service name for OpenSearch Serverless
)

client_kwargs["http_auth"] = aws_auth
client_kwargs["use_ssl"] = True
client_kwargs["verify_certs"] = True
client_kwargs["connection_class"] = AsyncHttpConnection
else:
raise InterpreterError(
f"Unsupported authentication type for DocumentIndex: {type(index.auth)}"
Expand Down
117 changes: 83 additions & 34 deletions ui/components/FlowResponseTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@

"use client";

import "react-data-grid/lib/styles.css";

import {
flexRender,
getCoreRowModel,
getFilteredRowModel,
getSortedRowModel,
useReactTable,
type ColumnDef,
type SortingState,
} from "@tanstack/react-table";
import { Download } from "lucide-react";
import Papa from "papaparse";
import { useMemo, useState } from "react";
import { DataGrid, type Column } from "react-data-grid";

import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
Expand Down Expand Up @@ -57,8 +63,9 @@ export default function FlowResponseTable({
outputs,
}: FlowResponseTableProps) {
const [searchText, setSearchText] = useState("");
const [sorting, setSorting] = useState<SortingState>([]);

const rows = useMemo(() => {
const data = useMemo(() => {
return outputs.map((output) => {
const outputData =
output && typeof output === "object"
Expand All @@ -68,43 +75,46 @@ export default function FlowResponseTable({
});
}, [outputs]);

const columns = useMemo<Column<Record<string, ResponseData>>[]>(() => {
const columns = useMemo<ColumnDef<Record<string, ResponseData>>[]>(() => {
if (!responseSchema?.properties) return [];

return Object.entries(responseSchema.properties).map(([key, schema]) => {
const prop = schema as SchemaProperty;
return {
key,
name: prop.title || key,
sortable: true,
resizable: true,
renderCell: ({ row }) => {
const value = row[key];
accessorKey: key,
header: prop.title || key,
cell: ({ row }) => {
const value = row.original[key];
return formatCellValue(value, prop.qtype_type);
},
};
});
}, [responseSchema]);

const filteredRows = useMemo(() => {
if (!searchText) return rows;

return rows.filter((row) =>
Object.values(row).some((value) =>
String(value).toLowerCase().includes(searchText.toLowerCase()),
),
);
}, [rows, searchText]);
const table = useReactTable({
data,
columns,
state: {
sorting,
globalFilter: searchText,
},
onSortingChange: setSorting,
onGlobalFilterChange: setSearchText,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
});

const handleDownloadCSV = () => {
const csvData = filteredRows.map((row) => {
const csvData = table.getFilteredRowModel().rows.map((row) => {
const rowData: Record<string, string> = {};
columns.forEach((col) => {
const propertySchema = responseSchema?.properties?.[
col.key as string
] as SchemaProperty | undefined;
rowData[col.name as string] = formatCellValue(
row[col.key as string],
const key = (col as { accessorKey: string }).accessorKey;
const propertySchema = responseSchema?.properties?.[key] as
| SchemaProperty
| undefined;
rowData[String(col.header)] = formatCellValue(
row.original[key],
propertySchema?.qtype_type,
);
});
Expand Down Expand Up @@ -157,17 +167,56 @@ export default function FlowResponseTable({
</Button>
</div>

<div className="rdg-light">
<DataGrid
columns={columns}
rows={filteredRows}
className="fill-grid"
style={{ height: "400px" }}
/>
<div className="border rounded-lg overflow-hidden">
<div className="overflow-auto" style={{ maxHeight: "400px" }}>
<table className="w-full text-sm">
<thead className="bg-gray-50 dark:bg-gray-900 sticky top-0">
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
className="px-4 py-2 text-left font-medium cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"
onClick={header.column.getToggleSortingHandler()}
>
<div className="flex items-center gap-2">
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
{{
asc: " 🔼",
desc: " 🔽",
}[header.column.getIsSorted() as string] ?? null}
</div>
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr
key={row.id}
className="border-t hover:bg-gray-50 dark:hover:bg-gray-900"
>
{row.getVisibleCells().map((cell) => (
<td key={cell.id} className="px-4 py-2">
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>

<div className="text-sm text-muted-foreground">
{filteredRows.length} row(s) total
{table.getFilteredRowModel().rows.length} row(s) total
</div>
</div>
);
Expand Down
45 changes: 34 additions & 11 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"papaparse": "^5.5.3",
"radix-ui": "^1.4.3",
"react": "^19.2.0",
"react-data-grid": "^7.0.0-beta.59",
"@tanstack/react-table": "^8.20.6",
"react-day-picker": "^9.8.1",
"react-dom": "^19.2.0",
"react-dropzone": "^14.3.8",
Expand Down