Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix results table display #62

Merged
merged 1 commit into from
Mar 21, 2024
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
x
  • Loading branch information
eyurtsev committed Mar 21, 2024
commit 2e8461d36fdc5dfba67e615bf0d0270f2ba56c4b
35 changes: 33 additions & 2 deletions frontend/app/components/Playground.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
"use client";

import { Button, Textarea, Heading } from "@chakra-ui/react";
import {
Button,
Textarea,
Heading,
Tab,
Tabs,
TabList,
TabPanel,
TabPanels,
Text,
} from "@chakra-ui/react";
import { useMutation } from "@tanstack/react-query";
import React from "react";
import SyntaxHighlighter from "react-syntax-highlighter";
import { docco } from "react-syntax-highlighter/dist/esm/styles/hljs";
import { runExtraction } from "../utils/api";
import { Extractor } from "./Extractor";
import { ResultsTable } from "./ResultsTable";
Expand Down Expand Up @@ -87,7 +99,26 @@ export const Playground = (props: PlaygroundProps) => {
</form>
</div>
<div className="m-auto">
<ResultsTable data={data} isPending={isPending} />
<Tabs>
<TabList>
<Tab>Table</Tab>
<Tab>JSON</Tab>
</TabList>
<TabPanels>
<TabPanel>
<ResultsTable data={data} isPending={isPending} />
</TabPanel>
<TabPanel>
<Text className="mt-1 mb-5">
This shows the raw JSON Schema that describes what information
the extractor will be extracting from the content.
</Text>
<SyntaxHighlighter language="json" style={docco}>
{JSON.stringify(data, null, 2)}
</SyntaxHighlighter>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</div>
);
Expand Down
56 changes: 46 additions & 10 deletions frontend/app/components/ResultsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,63 @@ import {
Tr,
} from "@chakra-ui/react";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getColumns(records: Array<Record<string, any>>): Array<any> {
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}

function getColumns(records: unknown[]): Array<string> {
// Create a set to store unique keys
const uniqueKeys = new Set();
const uniqueKeys = new Set<string>();

// Iterate over each record in the list
records.forEach((record) => {
// For each key in the current record, add it to the set
if (!isRecord(record)) {
return;
}
Object.keys(record).forEach((key) => {
uniqueKeys.add(key);
if (typeof key === "string") {
uniqueKeys.add(key);
}
});
});

// Convert the set back into an array and return it
return Array.from(uniqueKeys);
}

/*
* This function takes a value and returns a string representation of it.
* If the value is an array, it will join the elements with a comma and space.
* If the value is an object, it will create an array of strings representing
* each key-value pair, then join them with a comma and space.
* Otherwise, it will return the string representation of the value.
* @param value - The value to display
* @returns The string representation of the value
*/
function getDisplayValue(value: unknown): string {
if (Array.isArray(value)) {
return value.map(getDisplayValue).join(", ");
}
if (isRecord(value)) {
// Creating an array of strings representing each key-value pair,
// then joining them with a comma and space.
return Object.entries(value)
.map(([key, val]) => `${key}: ${getDisplayValue(val)}`)
.join(", ");
}
return String(value);
}

export const ResultsTable = ({
data,
isPending,
}: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: { data: Array<Record<string, any>> } | undefined;
data: { data: unknown[] } | undefined;
isPending: boolean;
}) => {
// scan all the results to determine the columns
// then display the results in a table
const actualData = data?.data;
const columns = actualData ? getColumns(actualData) : [];

if (isPending) {
return (
<Spinner
Expand All @@ -52,6 +79,9 @@ export const ResultsTable = ({
);
}

const actualData = data?.data;
const columns = actualData ? getColumns(actualData) : [];

return (
<div>
<TableContainer>
Expand All @@ -69,7 +99,13 @@ export const ResultsTable = ({
return (
<Tr key={index}>
{columns.map((column, idx) => (
<Td key={`table-data-${idx}`}>{row[column]}</Td>
// Check if the row has the column,
// if not, display an empty cell
<Td key={`table-cell-${idx}`}>
{isRecord(row) && column in row
? getDisplayValue(row[column])
: ""}
</Td>
))}
</Tr>
);
Expand Down
7 changes: 5 additions & 2 deletions frontend/app/utils/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ type ExtractionRequest = {
file?: File;
};

type ExtractionResponse = {
data: unknown[];
};

export const runExtraction: MutationFunction<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
any,
ExtractionResponse,
[ExtractionRequest, boolean]
> = async ([extractionRequest, isShared]) => {
const endpoint = isShared ? "extract/shared" : "extract";
Expand Down
Loading