diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json
index 363415ccf..afef59f3a 100644
--- a/src/frontend/package-lock.json
+++ b/src/frontend/package-lock.json
@@ -26,6 +26,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
+ "@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.32.0",
"@tailwindcss/forms": "^0.5.6",
@@ -2761,6 +2762,31 @@
}
}
},
+ "node_modules/@radix-ui/react-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
+ "integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-tooltip": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",
diff --git a/src/frontend/package.json b/src/frontend/package.json
index 053a246ee..39d595dcd 100644
--- a/src/frontend/package.json
+++ b/src/frontend/package.json
@@ -21,6 +21,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
+ "@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.6",
"@tabler/icons-react": "^2.32.0",
"@tailwindcss/forms": "^0.5.6",
diff --git a/src/frontend/src/components/tableComponent/components/tableToolbar.tsx/index.tsx b/src/frontend/src/components/tableComponent/components/tableToolbar.tsx/index.tsx
new file mode 100644
index 000000000..bbedbad0e
--- /dev/null
+++ b/src/frontend/src/components/tableComponent/components/tableToolbar.tsx/index.tsx
@@ -0,0 +1,3 @@
+export default function TableToolbar({ children }): JSX.Element {
+ return
{children}
;
+}
diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx
index 534ed171f..1a9c7a44d 100644
--- a/src/frontend/src/components/tableComponent/index.tsx
+++ b/src/frontend/src/components/tableComponent/index.tsx
@@ -1,7 +1,7 @@
import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid
import "ag-grid-community/styles/ag-theme-quartz.css"; // Optional Theme applied to the grid
import { AgGridReact, AgGridReactProps } from "ag-grid-react";
-import { ElementRef, forwardRef } from "react";
+import { ElementRef, forwardRef, useRef } from "react";
import {
DEFAULT_TABLE_ALERT_MSG,
DEFAULT_TABLE_ALERT_TITLE,
@@ -11,6 +11,9 @@ import "../../style/ag-theme-shadcn.css"; // Custom CSS applied to the grid
import { cn, toTitleCase } from "../../utils/utils";
import ForwardedIconComponent from "../genericIconComponent";
import { Alert, AlertDescription, AlertTitle } from "../ui/alert";
+import { Toggle } from "../ui/toggle";
+import ShadTooltip from "../shadTooltipComponent";
+import resetGrid from "./utils/reset-grid-columns";
interface TableComponentProps extends AgGridReactProps {
columnDefs: NonNullable;
@@ -32,27 +35,45 @@ const TableComponent = forwardRef<
},
ref,
) => {
+ const gridRef = useRef(null);
+ const realRef = ref?.current ? ref : gridRef;
const dark = useDarkStore((state) => state.dark);
- if (props.rowData.length === 0) {
- return (
-
-
-
- {alertTitle}
- {alertDescription}
-
-
- );
- }
- const colDef = props.columnDefs.map((col, index) => {
+ const makeLastColumnNonResizable = (columnDefs) => {
+ columnDefs.forEach((colDef, index) => {
+ colDef.resizable = index !== columnDefs.length - 1;
+ });
+ return columnDefs;
+ };
+
+ const onGridReady = (params) => {
+ realRef.current = params;
+ const updatedColumnDefs = makeLastColumnNonResizable([
+ ...props.columnDefs,
+ ]);
+ params.api.setColumnDefs(updatedColumnDefs);
+ if (props.onGridReady) props.onGridReady(params);
+ };
+
+ const onColumnMoved = (params) => {
+ const updatedColumnDefs = makeLastColumnNonResizable(
+ params.columnApi.getAllGridColumns().map((col) => col.getColDef()),
+ );
+ params.api.setColumnDefs(updatedColumnDefs);
+ if (props.onColumnMoved) props.onColumnMoved(params);
+ };
+
+ let colDef = props.columnDefs.map((col, index) => {
let newCol = {
...col,
headerName: toTitleCase(col.headerName),
};
+ if (index === props.columnDefs.length - 1) {
+ newCol = {
+ ...col,
+ resizable: false,
+ };
+ }
if (props.onSelectionChanged && index === 0) {
newCol = {
...newCol,
@@ -73,12 +94,28 @@ const TableComponent = forwardRef<
}
return newCol;
});
+ let rowDef = props.rowData;
+ if (props.rowData.length === 0) {
+ return (
+
+
+
+ {alertTitle}
+ {alertDescription}
+
+
+ );
+ }
return (
+ {/*
+
setShow(!show)}
+ >
+
+
+
+
*/}
+
+
+ {
+ resetGrid(realRef);
+ }}
+ >
+
+
+
+
);
},
diff --git a/src/frontend/src/components/tableComponent/utils/reset-grid-columns.tsx b/src/frontend/src/components/tableComponent/utils/reset-grid-columns.tsx
new file mode 100644
index 000000000..1ef2f58a1
--- /dev/null
+++ b/src/frontend/src/components/tableComponent/utils/reset-grid-columns.tsx
@@ -0,0 +1,5 @@
+export default function resetGrid(ref) {
+ if (ref?.current && ref?.current.api) {
+ ref.current.api.resetColumnState();
+ }
+}
diff --git a/src/frontend/src/components/ui/toggle.tsx b/src/frontend/src/components/ui/toggle.tsx
new file mode 100644
index 000000000..251103615
--- /dev/null
+++ b/src/frontend/src/components/ui/toggle.tsx
@@ -0,0 +1,45 @@
+"use client";
+
+import * as React from "react";
+import * as TogglePrimitive from "@radix-ui/react-toggle";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "../../utils/utils";
+
+const toggleVariants = cva(
+ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default: "bg-transparent",
+ outline:
+ "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
+ },
+ size: {
+ default: "h-10 px-3",
+ sm: "h-9 px-2.5",
+ lg: "h-11 px-5",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ },
+);
+
+const Toggle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, variant, size, ...props }, ref) => (
+
+));
+
+Toggle.displayName = TogglePrimitive.Root.displayName;
+
+export { Toggle, toggleVariants };
diff --git a/src/frontend/src/modals/IOModal/components/chatView/index.tsx b/src/frontend/src/modals/IOModal/components/chatView/index.tsx
index 8bc226074..6b122cf4c 100644
--- a/src/frontend/src/modals/IOModal/components/chatView/index.tsx
+++ b/src/frontend/src/modals/IOModal/components/chatView/index.tsx
@@ -138,7 +138,7 @@ export default function ChatView({
function updateChat(
chat: ChatMessageType,
message: string,
- stream_url?: string
+ stream_url?: string,
) {
// if (message === "") return;
chat.message = message;
@@ -177,7 +177,7 @@ export default function ChatView({
name="Eraser"
className={classNames(
"h-5 w-5 transition-all duration-100",
- lockChat ? "animate-pulse text-primary" : "text-primary"
+ lockChat ? "animate-pulse text-primary" : "text-primary",
)}
aria-hidden="true"
/>
diff --git a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx
index f4de52cbb..d7f4d5202 100644
--- a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx
+++ b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx
@@ -5,7 +5,7 @@ const useRemoveMessages = (
setSelectedRows,
setSuccessData,
setErrorData,
- selectedRows
+ selectedRows,
) => {
const deleteMessages = useMessagesStore((state) => state.removeMessages);
diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts
index e2c81eff6..8554d2f55 100644
--- a/src/frontend/src/stores/flowStore.ts
+++ b/src/frontend/src/stores/flowStore.ts
@@ -79,7 +79,7 @@ const useFlowStore = create((set, get) => ({
updateFlowPool: (
nodeId: string,
data: FlowPoolObjectType | ChatOutputType | chatInputType,
- buildId?: string
+ buildId?: string,
) => {
let newFlowPool = cloneDeep({ ...get().flowPool });
if (!newFlowPool[nodeId]) {
@@ -170,7 +170,7 @@ const useFlowStore = create((set, get) => ({
flowsManager.autoSaveCurrentFlow(
newChange,
newEdges,
- get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }
+ get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
);
}
},
@@ -186,7 +186,7 @@ const useFlowStore = create((set, get) => ({
flowsManager.autoSaveCurrentFlow(
get().nodes,
newChange,
- get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }
+ get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
);
}
},
@@ -204,7 +204,7 @@ const useFlowStore = create((set, get) => ({
return newChange;
}
return node;
- })
+ }),
);
},
getNode: (id: string) => {
@@ -215,8 +215,8 @@ const useFlowStore = create((set, get) => ({
get().nodes.filter((node) =>
typeof nodeId === "string"
? node.id !== nodeId
- : !nodeId.includes(node.id)
- )
+ : !nodeId.includes(node.id),
+ ),
);
},
deleteEdge: (edgeId) => {
@@ -224,8 +224,8 @@ const useFlowStore = create((set, get) => ({
get().edges.filter((edge) =>
typeof edgeId === "string"
? edge.id !== edgeId
- : !edgeId.includes(edge.id)
- )
+ : !edgeId.includes(edge.id),
+ ),
);
},
paste: (selection, position) => {
@@ -291,7 +291,7 @@ const useFlowStore = create((set, get) => ({
let source = idsMap[edge.source];
let target = idsMap[edge.target];
const sourceHandleObject: sourceHandleType = scapeJSONParse(
- edge.sourceHandle!
+ edge.sourceHandle!,
);
let sourceHandle = scapedJSONStringfy({
...sourceHandleObject,
@@ -301,7 +301,7 @@ const useFlowStore = create((set, get) => ({
edge.data.sourceHandle = sourceHandleObject;
const targetHandleObject: targetHandleType = scapeJSONParse(
- edge.targetHandle!
+ edge.targetHandle!,
);
let targetHandle = scapedJSONStringfy({
...targetHandleObject,
@@ -322,7 +322,7 @@ const useFlowStore = create((set, get) => ({
className: "stroke-gray-900 ",
selected: false,
},
- newEdges.map((edge) => ({ ...edge, selected: false }))
+ newEdges.map((edge) => ({ ...edge, selected: false })),
);
});
get().setEdges(newEdges);
@@ -341,10 +341,10 @@ const useFlowStore = create((set, get) => ({
});
const newNodes = get().nodes.filter(
- (node) => !nodesIdsSelected.includes(node.id)
+ (node) => !nodesIdsSelected.includes(node.id),
);
const newEdges = get().edges.filter(
- (edge) => !edgesIdsSelected.includes(edge.id)
+ (edge) => !edgesIdsSelected.includes(edge.id),
);
set({ nodes: newNodes, edges: newEdges });
@@ -402,7 +402,7 @@ const useFlowStore = create((set, get) => ({
style: { stroke: "#555" },
className: "stroke-foreground stroke-connection",
},
- oldEdges
+ oldEdges,
);
return newEdges;
@@ -412,7 +412,7 @@ const useFlowStore = create((set, get) => ({
.autoSaveCurrentFlow(
get().nodes,
newEdges,
- get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }
+ get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
);
},
unselectAll: () => {
@@ -443,7 +443,7 @@ const useFlowStore = create((set, get) => ({
function validateSubgraph(nodes: string[]) {
const errorsObjs = validateNodes(
get().nodes.filter((node) => nodes.includes(node.id)),
- get().edges
+ get().edges,
);
const errors = errorsObjs.map((obj) => obj.errors).flat();
@@ -462,14 +462,14 @@ const useFlowStore = create((set, get) => ({
function handleBuildUpdate(
vertexBuildData: VertexBuildTypeAPI,
status: BuildStatus,
- runId: string
+ runId: string,
) {
console.log("handleBuildUpdate", vertexBuildData, status, runId);
if (vertexBuildData && vertexBuildData.inactivated_vertices) {
get().removeFromVerticesBuild(vertexBuildData.inactivated_vertices);
get().updateBuildStatus(
vertexBuildData.inactivated_vertices,
- BuildStatus.INACTIVE
+ BuildStatus.INACTIVE,
);
}
@@ -485,14 +485,15 @@ const useFlowStore = create((set, get) => ({
// next_vertices_ids should be next_vertices_ids without the inactivated vertices
const next_vertices_ids = vertexBuildData.next_vertices_ids.filter(
- (id) => !vertexBuildData.inactivated_vertices?.includes(id)
+ (id) => !vertexBuildData.inactivated_vertices?.includes(id),
);
const top_level_vertices = vertexBuildData.top_level_vertices.filter(
- (vertex) => !vertexBuildData.inactivated_vertices?.includes(vertex.id)
+ (vertex) =>
+ !vertexBuildData.inactivated_vertices?.includes(vertex.id),
);
const nextVertices: VertexLayerElementType[] = zip(
next_vertices_ids,
- top_level_vertices
+ top_level_vertices,
).map(([id, reference]) => ({ id: id!, reference }));
const newLayers = [
@@ -514,7 +515,7 @@ const useFlowStore = create((set, get) => ({
get().addDataToFlowPool(
{ ...vertexBuildData, buildId: runId },
- vertexBuildData.id
+ vertexBuildData.id,
);
useFlowStore.getState().updateBuildStatus([vertexBuildData.id], status);
@@ -523,7 +524,7 @@ const useFlowStore = create((set, get) => ({
const newFlowBuildStatus = { ...get().flowBuildStatus };
// filter out the vertices that are not status
const verticesToUpdate = verticesIds?.filter(
- (id) => newFlowBuildStatus[id]?.status !== BuildStatus.BUILT
+ (id) => newFlowBuildStatus[id]?.status !== BuildStatus.BUILT,
);
if (verticesToUpdate) {
@@ -588,7 +589,7 @@ const useFlowStore = create((set, get) => ({
verticesLayers: VertexLayerElementType[][];
runId: string;
verticesToRun: string[];
- } | null
+ } | null,
) => {
set({ verticesBuild: vertices });
},
@@ -613,7 +614,7 @@ const useFlowStore = create((set, get) => ({
// that are going to be built
verticesIds: get().verticesBuild!.verticesIds.filter(
// keep the vertices that are not in the list of vertices to remove
- (vertex) => !vertices.includes(vertex)
+ (vertex) => !vertices.includes(vertex),
),
},
});
diff --git a/src/frontend/src/style/classes.css b/src/frontend/src/style/classes.css
index 39b080390..29140e7fa 100644
--- a/src/frontend/src/style/classes.css
+++ b/src/frontend/src/style/classes.css
@@ -15,6 +15,10 @@ pre {
font-family: inherit;
}
+.ag-paging-page-size {
+ display: none;
+}
+
.react-flow__pane {
cursor: default;
}
diff --git a/src/frontend/src/types/zustand/flow/index.ts b/src/frontend/src/types/zustand/flow/index.ts
index c421511de..6f995f5ec 100644
--- a/src/frontend/src/types/zustand/flow/index.ts
+++ b/src/frontend/src/types/zustand/flow/index.ts
@@ -78,7 +78,7 @@ export type FlowStoreType = {
state:
| FlowState
| undefined
- | ((oldState: FlowState | undefined) => FlowState)
+ | ((oldState: FlowState | undefined) => FlowState),
) => void;
nodes: Node[];
edges: Edge[];
@@ -86,11 +86,11 @@ export type FlowStoreType = {
onEdgesChange: OnEdgesChange;
setNodes: (
update: Node[] | ((oldState: Node[]) => Node[]),
- skipSave?: boolean
+ skipSave?: boolean,
) => void;
setEdges: (
update: Edge[] | ((oldState: Edge[]) => Edge[]),
- skipSave?: boolean
+ skipSave?: boolean,
) => void;
setNode: (id: string, update: Node | ((oldState: Node) => Node)) => void;
getNode: (id: string) => Node | undefined;
@@ -98,12 +98,12 @@ export type FlowStoreType = {
deleteEdge: (edgeId: string | Array) => void;
paste: (
selection: { nodes: any; edges: any },
- position: { x: number; y: number; paneX?: number; paneY?: number }
+ position: { x: number; y: number; paneX?: number; paneY?: number },
) => void;
lastCopiedSelection: { nodes: any; edges: any } | null;
setLastCopiedSelection: (
newSelection: { nodes: any; edges: any } | null,
- isCrop?: boolean
+ isCrop?: boolean,
) => void;
cleanFlow: () => void;
setFilterEdge: (newState) => void;
@@ -127,7 +127,7 @@ export type FlowStoreType = {
verticesLayers: VertexLayerElementType[][];
runId: string;
verticesToRun: string[];
- } | null
+ } | null,
) => void;
addToVerticesBuild: (vertices: string[]) => void;
removeFromVerticesBuild: (vertices: string[]) => void;
@@ -145,7 +145,7 @@ export type FlowStoreType = {
updateFlowPool: (
nodeId: string,
data: FlowPoolObjectType | ChatOutputType | chatInputType,
- buildId?: string
+ buildId?: string,
) => void;
getNodePosition: (nodeId: string) => { x: number; y: number };
};
diff --git a/src/frontend/src/utils/storeUtils.ts b/src/frontend/src/utils/storeUtils.ts
index 637e4331a..c8391b211 100644
--- a/src/frontend/src/utils/storeUtils.ts
+++ b/src/frontend/src/utils/storeUtils.ts
@@ -7,7 +7,7 @@ export default function cloneFLowWithParent(
flow: FlowType,
parent: string,
is_component: boolean,
- keepId = false
+ keepId = false,
) {
let childFLow = cloneDeep(flow);
childFLow.parent = parent;
diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts
index c73ec5d23..b1b6a6f25 100644
--- a/src/frontend/src/utils/styleUtils.ts
+++ b/src/frontend/src/utils/styleUtils.ts
@@ -143,6 +143,8 @@ import {
X,
XCircle,
Zap,
+ RotateCcw,
+ Settings,
} from "lucide-react";
import { FaApple, FaDiscord, FaGithub } from "react-icons/fa";
import { AWSIcon } from "../icons/AWS";
@@ -526,4 +528,6 @@ export const nodeIconsLucide: iconsType = {
FolderPlusIcon,
FolderIcon,
Discord: FaDiscord,
+ RotateCcw,
+ Settings,
};