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

22 add commonly used operations #28

Merged
merged 18 commits into from
Dec 26, 2023
Merged
Original file line number Diff line number Diff line change
@@ -1,13 +1,45 @@
import { fireEvent, render, screen } from "@testing-library/react";
import Operation from "../core/Operation";
import Port from "../core/Port";
import { ADD_DFDX_CODE, ADD_F_CODE } from "../features/BuiltInCode";
import {
ADD_DFDX_CODE,
ADD_F_CODE,
SIN_DFDX_CODE,
SIN_F_CODE,
SUM_DFDX_CODE,
SUM_F_CODE,
} from "../features/BuiltInCode";
import type FeatureNodeType from "../features/FeatureNodeType";
import type FeatureOperation from "../features/FeatureOperation";
import AddNodesPanel from "./AddNodesPanel";

jest.mock("./EditOperationDialogMenu");

test("should render operation types as headers", () => {
const featureOperations = getFeatureOperations();
const handleAddNode = jest.fn();
const handleAddOperation = jest.fn();
const handleEditOperation = jest.fn();
const handleDeleteOperation = jest.fn();
render(
<AddNodesPanel
featureOperations={featureOperations}
isDarkMode={false}
onAddNode={handleAddNode}
onAddOperation={handleAddOperation}
onEditOperation={handleEditOperation}
onDeleteOperation={handleDeleteOperation}
/>,
);

const basicHeader = screen.getByText("Basic");
const aggregateHeader = screen.getByText("Aggregate");
const trigonometricHeader = screen.getByText("Trigonometric");
expect(basicHeader).toBeInTheDocument();
expect(aggregateHeader).toBeInTheDocument();
expect(trigonometricHeader).toBeInTheDocument();
});

test("should trigger event when clicking item", () => {
const featureOperations = getFeatureOperations();
const handleAddNode = jest.fn();
Expand Down Expand Up @@ -143,11 +175,29 @@ const getFeatureOperations = (): FeatureOperation[] => {
{
id: "add",
text: "Add",
type: "SIMPLE",
type: "basic",
namePrefix: "a",
operation: new Operation(ADD_F_CODE, ADD_DFDX_CODE),
inputPorts: [new Port("a", false), new Port("b", false)],
helpText: "Add two numbers $ a + b $",
},
{
id: "sum",
text: "Sum",
type: "aggregate",
namePrefix: "s",
operation: new Operation(SUM_F_CODE, SUM_DFDX_CODE),
inputPorts: [new Port("x_i", true)],
helpText: "Add all inputs $ \\sum_i x_{i} $",
},
{
id: "sin",
text: "Sin",
type: "trigonometric",
namePrefix: "s",
operation: new Operation(SIN_F_CODE, SIN_DFDX_CODE),
inputPorts: [new Port("x", true)],
helpText: "Calculate $ \\sin(x) $",
},
];
};
94 changes: 60 additions & 34 deletions interactive-computational-graph/src/components/AddNodesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
Stack,
Typography,
} from "@mui/material";
import { useState, type FunctionComponent, useCallback } from "react";
import { useState, type FunctionComponent, useCallback, useMemo } from "react";
import type FeatureNodeType from "../features/FeatureNodeType";
import type FeatureOperation from "../features/FeatureOperation";
import DraggableItem from "./DraggableItem";
Expand All @@ -33,17 +33,24 @@ const AddNodesPanel: FunctionComponent<AddNodesPanelProps> = ({
onEditOperation,
onDeleteOperation,
}) => {
const simpleOperations = featureOperations.filter(
(operation) => operation.type === "SIMPLE",
const builtInOperationTypes: string[] = useMemo(
() => ["basic", "aggregate", "trigonometric", "activation", "loss"],
[],
);
const customOperations = featureOperations.filter(
(operation) => operation.type === "CUSTOM",

const customOperations = useMemo(
() => featureOperations.filter((operation) => operation.type === "custom"),
[featureOperations],
);

const [isEditDialogOpen, setEditDialogOpen] = useState(false);
const [editingOperation, setEditingOperation] =
useState<FeatureOperation | null>(null);

const capitalizeFirstLetter = useCallback((word: string): string => {
return word[0].toUpperCase() + word.slice(1);
}, []);

const handleOpenEditDialog = useCallback(
(featureOperation: FeatureOperation) => {
setEditingOperation(featureOperation);
Expand Down Expand Up @@ -114,35 +121,54 @@ const AddNodesPanel: FunctionComponent<AddNodesPanelProps> = ({
</AccordionDetails>
</Accordion>

{/* Simple operations */}
<Accordion defaultExpanded disableGutters square sx={{ width: "100%" }}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="simple-content"
id="simple-header"
>
<Typography variant="subtitle2">Simple</Typography>
</AccordionSummary>
<AccordionDetails id="simple-content" sx={{ p: 0 }}>
<List>
{simpleOperations.map((operation) => (
<DraggableItem
key={operation.id}
featureNodeType={{
nodeType: "OPERATION",
operationId: operation.id,
}}
text={operation.text}
editable
onClickItem={onAddNode}
onClickEditIcon={() => {
handleOpenEditDialog(operation);
}}
/>
))}
</List>
</AccordionDetails>
</Accordion>
{/* Built-in operations */}
{builtInOperationTypes.map((builtInOperationType) => {
const filteredOperations = featureOperations.filter(
(operation) => operation.type === builtInOperationType,
);

return (
<Accordion
key={builtInOperationType}
defaultExpanded
disableGutters
square
sx={{ width: "100%" }}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls={`${builtInOperationType}-content`}
id={`${builtInOperationType}-header`}
>
<Typography variant="subtitle2">
{capitalizeFirstLetter(builtInOperationType)}
</Typography>
</AccordionSummary>
<AccordionDetails
id={`${builtInOperationType}-content`}
sx={{ p: 0 }}
>
<List>
{filteredOperations.map((operation) => (
<DraggableItem
key={operation.id}
featureNodeType={{
nodeType: "OPERATION",
operationId: operation.id,
}}
text={operation.text}
editable
onClickItem={onAddNode}
onClickEditIcon={() => {
handleOpenEditDialog(operation);
}}
/>
))}
</List>
</AccordionDetails>
</Accordion>
);
})}

{/* Custom operations */}
<Accordion defaultExpanded disableGutters square sx={{ width: "100%" }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const getFeatureOperation = (): FeatureOperation => {
return {
id: "add",
text: "Add",
type: "SIMPLE",
type: "basic",
namePrefix: "a",
operation: new Operation(ADD_F_CODE, ADD_DFDX_CODE),
inputPorts: [new Port("a", false), new Port("b", false)],
Expand Down
Loading