Skip to content

Commit

Permalink
feat: implemented a SelectableSourceDataAGGrid component
Browse files Browse the repository at this point in the history
  • Loading branch information
alebg committed Sep 10, 2024
1 parent 93d0836 commit 0c6b95c
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 7 deletions.
10 changes: 7 additions & 3 deletions lib/components/dialog/CreateConversationDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export const CreateConversationDialog = ({
buttonAction,
...props
}: CreateConversationDialogProps) => {

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
Expand All @@ -70,13 +69,18 @@ export const CreateConversationDialog = ({
buttonAction(values);
};


const [isDialogOpen, setIsDialogOpen] = useState(isOpen);

return (
<ShadcnDialog open={isDialogOpen} {...props}>
<DialogTrigger asChild>
<Button variant="default" size="icon" label={<PenSquare />} disabled={!isEnabled} onClick={() => setIsDialogOpen(true)} />
<Button
variant="default"
size="icon"
label={<PenSquare />}
disabled={!isEnabled}
onClick={() => setIsDialogOpen(true)}
/>
</DialogTrigger>

<DialogContent
Expand Down
14 changes: 12 additions & 2 deletions lib/components/table/ConversationAGGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,13 @@ const NewConversationComponent = (
handleNewConversation(inputValues.conversationTitle);
};

return <CreateConversationDialog isEnabled={isEnabled} isOpen={isOpen} buttonAction={newConversationAction} />;
return (
<CreateConversationDialog
isEnabled={isEnabled}
isOpen={isOpen}
buttonAction={newConversationAction}
/>
);
};

/**
Expand Down Expand Up @@ -118,7 +124,11 @@ export function ConversationAGGrid(props: ConversationAGGridProps) {
rowData={props.rowData}
columnDefs={columnDefs}
additionalComponentsLeft={[
NewConversationComponent(props.newConversationIsEnabled, props.newConversationDialogIsOpen, props.handleNewConversation),
NewConversationComponent(
props.newConversationIsEnabled,
props.newConversationDialogIsOpen,
props.handleNewConversation,
),
]}
errorOverlayProps={props.errorOverlayProps}
// @ts-expect-error TODO: fix typing here somehow, passing "AGGridProps = { {context = ... } }" to "BaseAGGrid" doesn't work
Expand Down
107 changes: 107 additions & 0 deletions lib/components/table/SelectableSourceDataAGGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"use client";
import { z } from "zod";
import { BaseAGGrid } from "./BaseAGGrid";
import { ColDef } from "ag-grid-community";
import { useState } from "react";

import { Button as ShadcnButton } from "@/components/button/index";

const SourceDataRowSchema = z.object({
id: z.string(),
name: z.string(),
relativePath: z.string(),
createdAt: z.string(),
});

/**
* SourceDataRow is a type that represents the structure of the data that will be displayed in the AG Grid.
*/
export type SelectableSourceDataRow = z.infer<typeof SourceDataRowSchema>;

/**
* SourceDataAGGridProps is an interface that defines the props for the SourceDataAGGrid component.
* @param rowData: the data to be displayed in the AG Grid. Must be an array of SourceDataRow objects.
* @param buttonsWithCallBack: an array of objects containing a reactComponent and a callbackFunction.
*/
export interface SelectableSourceDataAGGridProps {
rowData: SelectableSourceDataRow[];
isLoading: boolean;
handleConfirmSelection: (selectedRows: SelectableSourceDataRow[]) => void;
errorOverlayProps?: {
errorStatus: boolean;
overlayText: string;
};
}

const ConfirmSelectionButton = ({ onClick }: { onClick: () => void }) => {
return (
<ShadcnButton
label={"Confirm Selection"}
variant="default"
onClick={onClick}
title="Confirm the selected rows"
/>
);
};

/**
* SourceDataAGGrid is a react component that displays a table of source data in an AG Grid.
* @param rowData: the data to be displayed in the AG Grid. Must be an array of SourceDataRow objects.
* @param handleDownloadSourceData: a function that is called when the download button is clicked.
* @param handleUploadSourceData: a function that is called when the upload button is clicked.
* @param isLoading: a boolean that indicates whether the data is still loading.
* @param errorOverlayProps: an object that contains the error status and overlay text.
* @returns a react component that displays a table of source data in an AG Grid.
*/
export function SelectableSourceDataAGGrid(
props: SelectableSourceDataAGGridProps,
) {
const [columnDefs] = useState<ColDef[]>([
{
headerCheckboxSelection: true,
headerCheckboxSelectionFilteredOnly: true,
checkboxSelection: true,
headerName: "ID",
filter: false,
field: "id",
flex: 0.3,
},
{
headerName: "Name",
field: "name",
flex: 1.5,
},
{
headerName: "Relative Path",
field: "relativePath",
flex: 2,
},
{
headerName: "Created At",
field: "createdAt",
flex: 1,
},
{
headerName: "",
filter: false,
flex: 0.5,
},
]);

return (
<div>
<BaseAGGrid
isLoading={props.isLoading}
rowData={props.rowData}
columnDefs={columnDefs}
componentsWithCallBack={[
{
reactComponent: ConfirmSelectionButton,
callbackFunction: props.handleConfirmSelection,
},
]}
errorOverlayProps={props.errorOverlayProps}
/>
</div>
);
}
3 changes: 1 addition & 2 deletions lib/components/table/SourceDataAGGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ const UploadSourceDataComponent = (
isUploading: boolean,
handleUploadSourceData: () => void,
) => {

if (!enableUpload) {
return null;
}
Expand Down Expand Up @@ -130,7 +129,7 @@ export function SourceDataAGGrid(props: SourceDataAGGridProps) {
isLoading={props.isLoading}
rowData={props.rowData}
columnDefs={columnDefs}
additionalComponentsLeft={[
additionalComponentsLeft={[
UploadSourceDataComponent(
props.enableUpload,
props.isUploading,
Expand Down
4 changes: 4 additions & 0 deletions lib/components/table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ export {
ConversationAGGrid,
type ConversationAGGridProps,
} from "./ConversationAGGrid";
export {
SelectableSourceDataAGGrid,
type SelectableSourceDataAGGridProps,
} from "./SelectableSourceDataAGGrid";
92 changes: 92 additions & 0 deletions stories/components/SelectableSourceDataAGGrid.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type { Meta, StoryObj } from "@storybook/react";

import {
SelectableSourceDataAGGrid,
SelectableSourceDataRow,
} from "@/components/table/SelectableSourceDataAGGrid";

const meta: Meta = {
title: "Components/AGGrid/SelectableSourceData",
component: SelectableSourceDataAGGrid,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
} satisfies Meta<typeof SelectableSourceDataAGGrid>;

export default meta;
type Story = StoryObj<typeof meta>;

function randomChoice<T>(list: T[]): T {
const randomIndex = Math.floor(Math.random() * list.length);
return list[randomIndex];
}

const thousand = Array.from({ length: 1000 }, (_, i) => i + 1);

function getRandomDate(start: Date, end: Date): Date {
const startTimestamp = start.getTime();
const endTimestamp = end.getTime();
const randomTimestamp =
startTimestamp + Math.random() * (endTimestamp - startTimestamp);
return new Date(randomTimestamp);
}

const dataGenerator = () => {
const topics = [
"wildfires",
"earthquakes",
"floods",
"hurricanes",
"tornadoes",
];
const file_number = randomChoice(thousand);
const extensions = ["txt", "csv", "json", "xml"];
const ext = randomChoice(extensions);
const relative_path = `/sda/${randomChoice<number>(thousand)}/${randomChoice<string>(topics)}/file_${file_number}.${ext}`;

const startDate_c = new Date(2024, 0, 1);
const endDate_c = new Date(2024, 1, 1);
const created_at = getRandomDate(startDate_c, endDate_c).toISOString();

const datum: SelectableSourceDataRow = {
id: randomChoice(thousand).toString(),
name: `File names can be long ${file_number}`,
relativePath: relative_path,
createdAt: created_at,
};

return datum;
};

export const LoadingWithNoData: Story = {
args: {
rowData: [],
isLoading: true,
},
};

export const ErrorState: Story = {
args: {
rowData: [],
isLoading: false,
errorOverlayProps: {
errorStatus: true,
overlayText:
"An error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus.an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus. an error occurred while fetching the data: lorem ipsum dolor sit amet, consectetur adipiscing elit. nullam nec purus. nullam nec purus. nullam nec purus.",
},
},
};

export const WithAlertFunctions: Story = {
args: {
rowData: Array.from({ length: 106 }, dataGenerator),
isLoading: false,
handleConfirmSelection: (selectedRows: SelectableSourceDataRow[]) => {
alert(
"Selected rows:\n\n" +
selectedRows.map((row) => JSON.stringify(row)).join("\n\n"),
);
},
},
};

0 comments on commit 0c6b95c

Please sign in to comment.