diff --git a/ui/admin/.eslintrc.cjs b/ui/admin/.eslintrc.cjs index 286a2ab0..d8df50b8 100644 --- a/ui/admin/.eslintrc.cjs +++ b/ui/admin/.eslintrc.cjs @@ -28,7 +28,7 @@ module.exports = { // React { files: ["**/*.{js,jsx,ts,tsx}"], - plugins: ["react", "jsx-a11y"], + plugins: ["react", "jsx-a11y", "react-compiler"], extends: [ "plugin:react/recommended", "plugin:react/jsx-runtime", @@ -50,6 +50,7 @@ module.exports = { }, rules: { "react/prop-types": "off", + "react-compiler/react-compiler": "error", "no-restricted-imports": [ "error", { diff --git a/ui/admin/app/components/ui/multi-select.tsx b/ui/admin/app/components/ui/multi-select.tsx index ea812909..095d01cc 100644 --- a/ui/admin/app/components/ui/multi-select.tsx +++ b/ui/admin/app/components/ui/multi-select.tsx @@ -181,6 +181,9 @@ const CommandEmpty = forwardRef< CommandEmpty.displayName = "CommandEmpty"; +/** + * @deprecated This component is super bulky and has some weird bugs. We need to create a new one that behaves similarly to ComboBox + */ const MultiSelect = React.forwardRef( ( { @@ -334,8 +337,13 @@ const MultiSelect = React.forwardRef( }; void exec(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]); + }, [ + debouncedSearchTerm, + groupBy, + open, + triggerSearchOnFocus, + onSearchSync, + ]); useEffect(() => { /** async search */ @@ -360,8 +368,13 @@ const MultiSelect = React.forwardRef( }; void exec(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]); + }, [ + debouncedSearchTerm, + groupBy, + open, + triggerSearchOnFocus, + onSearch, + ]); const CreatableItem = () => { if (!creatable) return undefined; diff --git a/ui/admin/app/components/ui/scroll-area.tsx b/ui/admin/app/components/ui/scroll-area.tsx index f193edb2..b7bc5efb 100644 --- a/ui/admin/app/components/ui/scroll-area.tsx +++ b/ui/admin/app/components/ui/scroll-area.tsx @@ -26,6 +26,9 @@ const ScrollArea = React.forwardRef< ...rootProps } = props; + const [viewportEl, setViewportEl] = React.useState( + null + ); const viewportRef = React.useRef(null); const [shouldStickToBottom, setShouldStickToBottom] = React.useState( enableScrollStick === "bottom" @@ -49,6 +52,11 @@ const ScrollArea = React.forwardRef< } }, [enableScrollStick, shouldStickToBottom, children]); + const initRef = React.useCallback((node: HTMLDivElement | null) => { + setViewportEl(node); + viewportRef.current = node; + }, []); + return ( setShouldStickToBottom(isScrolledToBottom(e.currentTarget)) } @@ -66,7 +74,7 @@ const ScrollArea = React.forwardRef< {enableScrollTo === "bottom" && ( setShouldStickToBottom(true)} - scrollContainerEl={viewportRef.current} + scrollContainerEl={viewportEl} disabled={shouldStickToBottom} /> )} diff --git a/ui/admin/app/components/ui/sidebar.tsx b/ui/admin/app/components/ui/sidebar.tsx index 0c9aace0..3d0c5717 100644 --- a/ui/admin/app/components/ui/sidebar.tsx +++ b/ui/admin/app/components/ui/sidebar.tsx @@ -17,8 +17,8 @@ import { } from "~/components/ui/tooltip"; import { useIsMobile } from "~/hooks/use-mobile"; -const SIDEBAR_COOKIE_NAME = "sidebar:state"; -const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; +const _SIDEBAR_COOKIE_NAME = "sidebar:state"; +const _SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; const SIDEBAR_WIDTH = "13rem"; const SIDEBAR_WIDTH_MOBILE = "18rem"; const SIDEBAR_WIDTH_ICON = "3rem"; @@ -81,9 +81,6 @@ const SidebarProvider = React.forwardRef< } _setOpen(value); - - // This sets the cookie to keep the sidebar state. - document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; }, [setOpenProp, open] ); diff --git a/ui/admin/app/components/ui/textarea.tsx b/ui/admin/app/components/ui/textarea.tsx index 6b35c544..b99fb045 100644 --- a/ui/admin/app/components/ui/textarea.tsx +++ b/ui/admin/app/components/ui/textarea.tsx @@ -128,14 +128,14 @@ const useAutosizeTextArea = ({ setInit(false); } - node.style.height = `${ - Math.min(Math.max(node.scrollHeight, minHeight), maxHeight) + - offsetBorder - }px`; + const newHeight = Math.min( + Math.max(node.scrollHeight, minHeight + offsetBorder), + maxHeight + offsetBorder + ); + + node.style.height = `${newHeight}px`; }, - // disable exhaustive deps because we don't want to rerun this after init is set to false - // eslint-disable-next-line react-hooks/exhaustive-deps - [maxHeight, minHeight] + [maxHeight, minHeight, setInit, init] ); const initResizer = React.useCallback( @@ -145,6 +145,7 @@ const useAutosizeTextArea = ({ node.oninput = () => resize(node); node.onresize = () => resize(node); node.onchange = () => resize(node); + resize(node); }, [resize] @@ -153,15 +154,14 @@ const useAutosizeTextArea = ({ React.useEffect(() => { if (textAreaRef) { initResizer(textAreaRef); - resize(textAreaRef); } - }, [resize, initResizer, textAreaRef]); + }, [initResizer, textAreaRef]); return { initResizer }; }; export type AutosizeTextAreaRef = { - textArea: HTMLTextAreaElement; + textArea: HTMLTextAreaElement | null; maxHeight: number; minHeight: number; }; @@ -185,28 +185,27 @@ const AutosizeTextarea = React.forwardRef< }: AutosizeTextAreaProps, ref: React.Ref ) => { - const textAreaRef = React.useRef(null); + const [textAreaEl, setTextAreaEl] = + React.useState(null); useImperativeHandle(ref, () => ({ - textArea: textAreaRef.current as HTMLTextAreaElement, - focus: textAreaRef?.current?.focus, + textArea: textAreaEl, + focus: textAreaEl?.focus, maxHeight, minHeight, })); const { initResizer } = useAutosizeTextArea({ - textAreaRef: textAreaRef.current, + textAreaRef: textAreaEl, maxHeight, minHeight, }); const initRef = React.useCallback( (node: HTMLTextAreaElement | null) => { - textAreaRef.current = node; - - if (!node) return; + setTextAreaEl(node); - initResizer(node); + if (node) initResizer(node); }, [initResizer] ); @@ -214,6 +213,7 @@ const AutosizeTextarea = React.forwardRef< return (