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 799fdbb2a..7d99ef457 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, useEffect, useRef, useState } from "react"; import { DEFAULT_TABLE_ALERT_MSG, DEFAULT_TABLE_ALERT_TITLE, @@ -11,6 +11,13 @@ 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 { Select, SelectContent, SelectTrigger } from "../ui/select"; +import { SelectItem } from "@radix-ui/react-select"; +import { Button } from "../ui/button"; +import { Toggle } from "../ui/toggle"; +import TableToolbar from "./components/tableToolbar.tsx"; +import ShadTooltip from "../shadTooltipComponent"; +import resetGrid from "./utils/reset-grid-columns"; interface TableComponentProps extends AgGridReactProps { columnDefs: NonNullable; @@ -32,7 +39,67 @@ const TableComponent = forwardRef< }, ref, ) => { + const gridRef = useRef(null); + const realRef = ref?.current ? ref : gridRef; const dark = useDarkStore((state) => state.dark); + + 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, + checkboxSelection: true, + headerCheckboxSelection: true, + headerCheckboxSelectionFilteredOnly: true, + }; + } + if ( + (typeof props.editable === "boolean" && props.editable) || + (Array.isArray(props.editable) && + props.editable.includes(newCol.headerName ?? "")) + ) { + newCol = { + ...newCol, + editable: true, + }; + } + return newCol; + }); + let rowDef = props.rowData; + if (props.rowData.length === 0) { return (
@@ -47,39 +114,12 @@ const TableComponent = forwardRef<
); } - - const colDef = props.columnDefs.map((col, index) => { - let newCol = { - ...col, - headerName: toTitleCase(col.headerName), - }; - if (props.onSelectionChanged && index === 0) { - newCol = { - ...newCol, - checkboxSelection: true, - headerCheckboxSelection: true, - headerCheckboxSelectionFilteredOnly: true, - }; - } - console.log(props.editable, col.headerName); - if ( - (typeof props.editable === "boolean" && props.editable) || - (Array.isArray(props.editable) && - props.editable.includes(newCol.headerName ?? "")) - ) { - newCol = { - ...newCol, - editable: true, - }; - } - return newCol; - }); - 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/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, };