diff --git a/package-lock.json b/package-lock.json index b0f83095..28f19d3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,13 +61,14 @@ "@typescript-eslint/eslint-plugin": "8.44.1", "@typescript-eslint/parser": "8.44.1", "@vitejs/plugin-react": "5.0.3", + "babel-plugin-react-compiler": "19.1.0-rc.3", "eslint": "9.36.0", "eslint-config-prettier": "10.1.8", "eslint-plugin-import": "2.32.0", "eslint-plugin-prettier": "5.5.4", "eslint-plugin-promise": "7.2.1", "eslint-plugin-react": "7.37.5", - "eslint-plugin-react-hooks": "5.2.0", + "eslint-plugin-react-hooks": "6.0.0-rc.2", "eslint-plugin-react-refresh": "0.4.21", "globals": "16.4.0", "postcss": "8.5.6", @@ -227,6 +228,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", @@ -254,6 +268,38 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -264,6 +310,20 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", @@ -296,6 +356,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", @@ -306,6 +379,38 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -366,6 +471,24 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", @@ -3709,6 +3832,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/babel-plugin-react-compiler": { + "version": "19.1.0-rc.3", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.1.0-rc.3.tgz", + "integrity": "sha512-mjRn69WuTz4adL0bXGx8Rsyk1086zFJeKmes6aK0xPuK3aaXmDJdLHqwKKMrpm6KAI1MCoUK72d2VeqQbu8YIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4829,18 +4962,36 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "version": "6.0.0-rc.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-6.0.0-rc.2.tgz", + "integrity": "sha512-2cnFkQl2xld2BgKDtxLSd/JqkpZHBXZKcz+ZurfiQ7GECzMckIddJN5PZyWach3MN4h/CjwfqPigAtYxInXtuw==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "hermes-parser": "^0.25.1", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, + "node_modules/eslint-plugin-react-hooks/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/eslint-plugin-react-refresh": { "version": "0.4.21", "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.21.tgz", @@ -5489,6 +5640,23 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -8853,6 +9021,19 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-validation-error": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.5.3.tgz", + "integrity": "sha512-OT5Y8lbUadqVZCsnyFaTQ4/O2mys4tj7PqhdbBCp7McPwvIEKfPtdA6QfPeFQK2/Rz5LgwmAXRJTugBNBi0btw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/package.json b/package.json index 17284d21..cd932b1e 100644 --- a/package.json +++ b/package.json @@ -70,13 +70,14 @@ "@typescript-eslint/eslint-plugin": "8.44.1", "@typescript-eslint/parser": "8.44.1", "@vitejs/plugin-react": "5.0.3", + "babel-plugin-react-compiler": "19.1.0-rc.3", "eslint": "9.36.0", "eslint-config-prettier": "10.1.8", "eslint-plugin-import": "2.32.0", "eslint-plugin-prettier": "5.5.4", "eslint-plugin-promise": "7.2.1", "eslint-plugin-react": "7.37.5", - "eslint-plugin-react-hooks": "5.2.0", + "eslint-plugin-react-hooks": "6.0.0-rc.2", "eslint-plugin-react-refresh": "0.4.21", "globals": "16.4.0", "postcss": "8.5.6", diff --git a/src/components/CollaboratorAnchor/CollaboratorAnchor.tsx b/src/components/CollaboratorAnchor/CollaboratorAnchor.tsx index 5a5f0b89..a4e6439a 100644 --- a/src/components/CollaboratorAnchor/CollaboratorAnchor.tsx +++ b/src/components/CollaboratorAnchor/CollaboratorAnchor.tsx @@ -1,4 +1,4 @@ -import { MouseEvent, ReactNode, useCallback } from "react"; +import { MouseEvent, ReactNode } from "react"; import { Anchor, AnchorProps, @@ -77,14 +77,11 @@ export const CollaboratorAnchor = ({ } } - const clickHandler = useCallback( - (event: MouseEvent) => { - if (onClick) { - onClick(event); - } - }, - [onClick] - ); + const clickHandler = (event: MouseEvent) => { + if (onClick) { + onClick(event); + } + }; return ( ("asc"); // Filter and sort the list based on user selections - const filteredList = useMemo( - () => - list - .filter((item) => filteredActivities.includes(item.type)) - .sort((a, b) => { - if (sort === "asc") { - return a.date - b.date; - } + const filteredList = list + .filter((item) => filteredActivities.includes(item.type)) + .sort((a, b) => { + if (sort === "asc") { + return a.date - b.date; + } - return b.date - a.date; - }), - [filteredActivities, list, sort] - ); + return b.date - a.date; + }); // Keep common card props in one place for easier adjustments // and to ensure consistency across different card types @@ -66,12 +62,9 @@ export const StepTimeline = ({ // Determine if comments are visible based on current filters // This helps to decide whether to show the "new comment" card or not // As there is no point in showing it if comments are filtered out. - const commentsVisible = useMemo( - () => - filteredActivities.includes(ActivityType.Comment) || - filteredActivities.includes(ActivityType.UnsolvedComment), - [filteredActivities] - ); + const commentsVisible = + filteredActivities.includes(ActivityType.Comment) || + filteredActivities.includes(ActivityType.UnsolvedComment); const newCommentItem = commentsVisible ? ( = ({ setOpened((opened) => !opened); }; - const onConfirmHandler = useCallback( - (event: MouseEvent) => { - setOpened(false); + const onConfirmHandler = (event: MouseEvent) => { + setOpened(false); - if (onConfirm) { - onConfirm(event); - } - }, - [onConfirm] - ); + if (onConfirm) { + onConfirm(event); + } + }; const popoverClickHandler = (event: MouseEvent) => { event.stopPropagation(); diff --git a/src/components/commentsList/CommentsList.tsx b/src/components/commentsList/CommentsList.tsx index bd8ef8c9..f50f38a5 100644 --- a/src/components/commentsList/CommentsList.tsx +++ b/src/components/commentsList/CommentsList.tsx @@ -68,18 +68,12 @@ export function CommentsList({ }, }); - const toggleIsResolved = useCallback( - (comment: TComment) => { - updateCommentResolved(!comment.resolved, comment.id); - }, - [updateCommentResolved] - ); - const updateContent = useCallback( - (content: string, comment: TComment) => { - updateCommentContent(content, comment.id); - }, - [updateCommentContent] - ); + const toggleIsResolved = (comment: TComment) => { + updateCommentResolved(!comment.resolved, comment.id); + }; + const updateContent = (content: string, comment: TComment) => { + updateCommentContent(content, comment.id); + }; // Compute select type filter options const filterOptions = useMemo(() => { @@ -134,10 +128,8 @@ export function CommentsList({ ]); // Sort comments - const computedComments = useMemo( - () => - filteredComments.toSorted((a, b) => (a.createdAt > b.createdAt ? -1 : 1)), - [filteredComments] + const computedComments = filteredComments.toSorted((a, b) => + a.createdAt > b.createdAt ? -1 : 1 ); if (!project.data?.id) { diff --git a/src/components/layout/SideBar/Overview/Overview.tsx b/src/components/layout/SideBar/Overview/Overview.tsx index f99d49e3..5b8436e3 100644 --- a/src/components/layout/SideBar/Overview/Overview.tsx +++ b/src/components/layout/SideBar/Overview/Overview.tsx @@ -65,9 +65,7 @@ export const Overview = ({ toggle }: OverviewProps) => { const openSidebar = () => toggle(SIDEBAR_STATUS.OPEN); - const expandCollapseClick = useCallback(() => { - setExpanded((expanded) => !expanded); - }, [setExpanded]); + const expandCollapseClick = () => setExpanded((expanded) => !expanded); const bulkLoadHandler = useCallback( (values: string[]) => { diff --git a/src/components/layout/SideBar/Overview/OverviewFilters/AssigneeFilter/AssigneeFilter.tsx b/src/components/layout/SideBar/Overview/OverviewFilters/AssigneeFilter/AssigneeFilter.tsx index aae38254..d5b6bad4 100644 --- a/src/components/layout/SideBar/Overview/OverviewFilters/AssigneeFilter/AssigneeFilter.tsx +++ b/src/components/layout/SideBar/Overview/OverviewFilters/AssigneeFilter/AssigneeFilter.tsx @@ -31,16 +31,13 @@ export const AssigneeFilter = ({ [toggle, onChange] ); - const clearFilterHandler = useCallback( - (event: MouseEvent) => { - event.stopPropagation(); + const clearFilterHandler = (event: MouseEvent) => { + event.stopPropagation(); - if (onChange) { - onChange(null); - } - }, - [onChange] - ); + if (onChange) { + onChange(null); + } + }; return ( diff --git a/src/components/layout/SideBar/Overview/TestRow.tsx b/src/components/layout/SideBar/Overview/TestRow.tsx index a8b5207f..e29f395b 100644 --- a/src/components/layout/SideBar/Overview/TestRow.tsx +++ b/src/components/layout/SideBar/Overview/TestRow.tsx @@ -1,4 +1,4 @@ -import { MouseEvent, useCallback, useEffect } from "react"; +import { MouseEvent, useEffect } from "react"; import clsx from "clsx"; import { useNavigate } from "react-router"; import { Box, Collapse, Flex, Progress, Table, Text } from "@mantine/core"; @@ -37,15 +37,12 @@ export const TestRow = ({ const navigate = useNavigate(); - const onExpandToggle = useCallback( - (e: MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); + const onExpandToggle = (e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); - toggle(); - }, - [toggle] - ); + toggle(); + }; useEffect(() => { if (forceExpanded) { diff --git a/src/components/modals/ResetProjectModal/ResetProjectModal.tsx b/src/components/modals/ResetProjectModal/ResetProjectModal.tsx index 97bebf69..e036451b 100644 --- a/src/components/modals/ResetProjectModal/ResetProjectModal.tsx +++ b/src/components/modals/ResetProjectModal/ResetProjectModal.tsx @@ -1,4 +1,3 @@ -import { useCallback } from "react"; import { Button, Checkbox, Group, Stack } from "@mantine/core"; import { useForm } from "@mantine/form"; import { ContextModalProps } from "@mantine/modals"; @@ -27,19 +26,14 @@ export function ResetProjectModal({ validate: {}, }); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: ResetProjectModalFormValues) => { - if (handleSubmit) { - handleSubmit(values); - } - close(); - }, - [close, handleSubmit] - ); + const handleFormSubmit = (values: ResetProjectModalFormValues) => { + if (handleSubmit) { + handleSubmit(values); + } + close(); + }; return (
diff --git a/src/components/modals/addServerModal/AddServerModal.tsx b/src/components/modals/addServerModal/AddServerModal.tsx index 3e795d1a..9a2192fa 100644 --- a/src/components/modals/addServerModal/AddServerModal.tsx +++ b/src/components/modals/addServerModal/AddServerModal.tsx @@ -1,4 +1,3 @@ -import { useCallback } from "react"; import { Button, Group, Stack, TextInput } from "@mantine/core"; import { isNotEmpty, useForm } from "@mantine/form"; import { ContextModalProps } from "@mantine/modals"; @@ -34,19 +33,14 @@ export function AddServerModal({ }, }); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: AddServerFormValues) => { - if (handleSubmit) { - handleSubmit(values); - } - close(); - }, - [close, handleSubmit] - ); + const handleFormSubmit = (values: AddServerFormValues) => { + if (handleSubmit) { + handleSubmit(values); + } + close(); + }; return ( diff --git a/src/components/modals/changeStatusModal/ChangeStatusModal.tsx b/src/components/modals/changeStatusModal/ChangeStatusModal.tsx index 6f478b19..56eda86f 100644 --- a/src/components/modals/changeStatusModal/ChangeStatusModal.tsx +++ b/src/components/modals/changeStatusModal/ChangeStatusModal.tsx @@ -45,30 +45,21 @@ export function ChangeStatusModal({ }, }); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: ChangeStatusFormValues) => { - if (handleSubmit) { - handleSubmit(values); - } - close(); - }, - [close, handleSubmit] - ); - - const nameOptions = useMemo(() => { - if (project.data?.collaborators) { - return (project.data.collaborators ?? []) - .concat(USER_ANONYMOUS) - .map((collaborator) => ({ - label: collaborator.name, - value: collaborator.id, - })); + const handleFormSubmit = (values: ChangeStatusFormValues) => { + if (handleSubmit) { + handleSubmit(values); } - }, [project.data?.collaborators]); + close(); + }; + + const nameOptions = (project.data?.collaborators ?? []) + .concat(USER_ANONYMOUS) + .map((collaborator) => ({ + label: collaborator.name, + value: collaborator.id, + })); const onStatusChange = useCallback( (status: StatusEnum) => { diff --git a/src/components/modals/cloneProjectModal/CloneProjectModal.tsx b/src/components/modals/cloneProjectModal/CloneProjectModal.tsx index 5747f221..2ceb22aa 100644 --- a/src/components/modals/cloneProjectModal/CloneProjectModal.tsx +++ b/src/components/modals/cloneProjectModal/CloneProjectModal.tsx @@ -1,4 +1,3 @@ -import { useCallback, useMemo } from "react"; import { Button, Checkbox, @@ -46,28 +45,19 @@ export function CloneProjectModal({ }, }); - const serversOptions = useMemo( - () => - Object.values(servers).map((server) => ({ - value: server.id, - label: server.name, - })), - [servers] - ); + const serversOptions = Object.values(servers).map((server) => ({ + value: server.id, + label: server.name, + })); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: CloneProjectModalFormValues) => { - if (handleSubmit) { - handleSubmit(values); - } - close(); - }, - [close, handleSubmit] - ); + const handleFormSubmit = (values: CloneProjectModalFormValues) => { + if (handleSubmit) { + handleSubmit(values); + } + close(); + }; return ( diff --git a/src/components/modals/collaboratorModal/CollaboratorModal.tsx b/src/components/modals/collaboratorModal/CollaboratorModal.tsx index a892e6e0..a064be59 100644 --- a/src/components/modals/collaboratorModal/CollaboratorModal.tsx +++ b/src/components/modals/collaboratorModal/CollaboratorModal.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect } from "react"; +import { useEffect } from "react"; import { Button, Group, Stack, TextInput } from "@mantine/core"; import { isNotEmpty, useForm } from "@mantine/form"; import { ContextModalProps } from "@mantine/modals"; @@ -30,19 +30,14 @@ export function CollaboratorModal({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [form.setValues, initialValues]); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: TCollaboratorDynamicData) => { - if (handleSubmit) { - handleSubmit(values, collaboratorId); - } - close(); - }, - [close, collaboratorId, handleSubmit] - ); + const handleFormSubmit = (values: TCollaboratorDynamicData) => { + if (handleSubmit) { + handleSubmit(values, collaboratorId); + } + close(); + }; return ( diff --git a/src/components/modals/confirmModal/ConfirmModal.tsx b/src/components/modals/confirmModal/ConfirmModal.tsx index 55eecd9e..321f75cf 100644 --- a/src/components/modals/confirmModal/ConfirmModal.tsx +++ b/src/components/modals/confirmModal/ConfirmModal.tsx @@ -1,4 +1,4 @@ -import { ReactNode, useCallback } from "react"; +import { ReactNode } from "react"; import { Button, ButtonProps, Group, Stack } from "@mantine/core"; import { ContextModalProps } from "@mantine/modals"; @@ -25,23 +25,21 @@ export function ConfirmModal({ cancelButtonProps = {}, }, }: ContextModalProps) { - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const cancelHandler = useCallback(() => { + const cancelHandler = () => { if (handleCancel) { handleCancel(); } close(); - }, [close, handleCancel]); + }; - const confirmHandler = useCallback(() => { + const confirmHandler = () => { if (handleConfirm) { handleConfirm(); } close(); - }, [close, handleConfirm]); + }; return ( diff --git a/src/components/modals/copyProjectToServer/CopyProjectToServer.tsx b/src/components/modals/copyProjectToServer/CopyProjectToServer.tsx index 0745783b..03d2a65b 100644 --- a/src/components/modals/copyProjectToServer/CopyProjectToServer.tsx +++ b/src/components/modals/copyProjectToServer/CopyProjectToServer.tsx @@ -31,19 +31,14 @@ export function CopyProjectToServer({ }, }); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: CopyProjectToServerFormValues) => { - if (handleSubmit) { - handleSubmit(values); - } - close(); - }, - [close, handleSubmit] - ); + const handleFormSubmit = (values: CopyProjectToServerFormValues) => { + if (handleSubmit) { + handleSubmit(values); + } + close(); + }; const serversOptions = useMemo( () => diff --git a/src/components/modals/createTestbookModal/CreateTestbookModal.tsx b/src/components/modals/createTestbookModal/CreateTestbookModal.tsx index 237050cc..5d0663ce 100644 --- a/src/components/modals/createTestbookModal/CreateTestbookModal.tsx +++ b/src/components/modals/createTestbookModal/CreateTestbookModal.tsx @@ -1,4 +1,3 @@ -import { useCallback } from "react"; import { Button, Group, Stack, TextInput } from "@mantine/core"; import { isNotEmpty, useForm } from "@mantine/form"; import { ContextModalProps } from "@mantine/modals"; @@ -25,19 +24,14 @@ export function CreateTestbookModal({ }, }); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: TProjectDynamicData) => { - if (handleSubmit) { - handleSubmit(values); - } - close(); - }, - [close, handleSubmit] - ); + const handleFormSubmit = (values: TProjectDynamicData) => { + if (handleSubmit) { + handleSubmit(values); + } + close(); + }; return ( diff --git a/src/components/modals/insertImageModal/InsertImageModal.tsx b/src/components/modals/insertImageModal/InsertImageModal.tsx index cc9e0938..754825de 100644 --- a/src/components/modals/insertImageModal/InsertImageModal.tsx +++ b/src/components/modals/insertImageModal/InsertImageModal.tsx @@ -1,4 +1,3 @@ -import { useCallback } from "react"; import { IconLink, IconUpload } from "@tabler/icons-react"; import { Tabs } from "@mantine/core"; import { ContextModalProps } from "@mantine/modals"; @@ -15,26 +14,21 @@ export const InsertImageModal = ({ context, innerProps: { handleCancel, handleSubmit }, }: ContextModalProps) => { - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const cancelHandler = useCallback(() => { + const cancelHandler = () => { if (handleCancel) { handleCancel(); } close(); - }, [close, handleCancel]); + }; - const submitHandler = useCallback( - (value: string) => { - if (handleSubmit) { - handleSubmit(value); - } - close(); - }, - [close, handleSubmit] - ); + const submitHandler = (value: string) => { + if (handleSubmit) { + handleSubmit(value); + } + close(); + }; return ( diff --git a/src/components/modals/promptModal/PromptModal.tsx b/src/components/modals/promptModal/PromptModal.tsx index d0e491f8..9009b25a 100644 --- a/src/components/modals/promptModal/PromptModal.tsx +++ b/src/components/modals/promptModal/PromptModal.tsx @@ -48,22 +48,19 @@ export function PromptModal({ validation, }, }: ContextModalProps) { - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); const field = useField({ initialValue, validate: validation ?? undefined, }); - const cancelHandler = useCallback(() => { + const cancelHandler = () => { if (handleCancel) { handleCancel(); } close(); - }, [close, handleCancel]); - + }; const submitHandler = useCallback(() => { field.validate().then((errors) => { if (errors) { diff --git a/src/components/modals/testCaseModal/TestCaseModal.tsx b/src/components/modals/testCaseModal/TestCaseModal.tsx index f20b48d8..994fa3b9 100644 --- a/src/components/modals/testCaseModal/TestCaseModal.tsx +++ b/src/components/modals/testCaseModal/TestCaseModal.tsx @@ -1,4 +1,3 @@ -import { useCallback } from "react"; import { Button, Group, Stack, TextInput } from "@mantine/core"; import { isNotEmpty, useForm } from "@mantine/form"; import { ContextModalProps } from "@mantine/modals"; @@ -23,20 +22,15 @@ export function TestCaseModal({ }, }); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: TCaseDynamicData) => { - if (handleSubmit) { - handleSubmit(values, caseId); - } + const handleFormSubmit = (values: TCaseDynamicData) => { + if (handleSubmit) { + handleSubmit(values, caseId); + } - close(); - }, - [close, handleSubmit, caseId] - ); + close(); + }; return ( diff --git a/src/components/modals/testModal/TestModal.tsx b/src/components/modals/testModal/TestModal.tsx index 79a3a30e..b17d7b34 100644 --- a/src/components/modals/testModal/TestModal.tsx +++ b/src/components/modals/testModal/TestModal.tsx @@ -31,20 +31,15 @@ export function TestModal({ }, }); - const close = useCallback(() => { - context.closeModal(id); - }, [context, id]); + const close = () => context.closeModal(id); - const handleFormSubmit = useCallback( - (values: TTestModalForm) => { - if (handleSubmit) { - handleSubmit(values, testId); - } + const handleFormSubmit = (values: TTestModalForm) => { + if (handleSubmit) { + handleSubmit(values, testId); + } - close(); - }, - [close, handleSubmit, testId] - ); + close(); + }; const assigneesChangeHandler = useCallback( (values: string[]) => form.setFieldValue("assignees", values), diff --git a/src/components/repositories/partials/ProjectList.tsx b/src/components/repositories/partials/ProjectList.tsx index 22c98e51..a5e5996f 100644 --- a/src/components/repositories/partials/ProjectList.tsx +++ b/src/components/repositories/partials/ProjectList.tsx @@ -1,4 +1,3 @@ -import { useMemo } from "react"; import { AnyDocumentId } from "@automerge/automerge-repo"; import { useDocument } from "@automerge/automerge-repo-react-hooks"; import { IconCloudUp, IconCopy } from "@tabler/icons-react"; @@ -41,13 +40,10 @@ export const ProjectList = ({ repo, repositoryId }: ProjectListProps) => { const navigate = useNavigate(); - const hasRemoteServers = useMemo(() => { - return ( - Object.values(servers).filter( - (server) => server.type === REPOSITORY_TYPE.remote - ).length > 0 - ); - }, [servers]); + const hasRemoteServers = + Object.values(servers).filter( + (server) => server.type === REPOSITORY_TYPE.remote + ).length > 0; return ( <> diff --git a/src/components/shared/DeleteActionIcon.tsx b/src/components/shared/DeleteActionIcon.tsx index ca28d67d..3fbce883 100644 --- a/src/components/shared/DeleteActionIcon.tsx +++ b/src/components/shared/DeleteActionIcon.tsx @@ -1,4 +1,4 @@ -import { MouseEvent, useCallback } from "react"; +import { MouseEvent } from "react"; import { IconX } from "@tabler/icons-react"; import { ActionIcon, ActionIconProps } from "@mantine/core"; @@ -10,14 +10,11 @@ export const DeleteActionIcon = ({ onClick, ...rest }: TDeleteActionIconProps) => { - const clickHandler = useCallback( - (event: MouseEvent) => { - if (onClick) { - onClick(event); - } - }, - [onClick] - ); + const clickHandler = (event: MouseEvent) => { + if (onClick) { + onClick(event); + } + }; return ( { const statusChanges = project.getStatusChangesByStepId(stepId); - const collaborators = useMemo(() => { - return (project.data?.collaborators ?? [])?.concat(USER_ANONYMOUS); - }, [project.data?.collaborators]); + const collaborators = (project.data?.collaborators ?? [])?.concat( + USER_ANONYMOUS + ); return ( diff --git a/src/components/stepDetails/stepDetails.tsx b/src/components/stepDetails/stepDetails.tsx index 518205a0..63685a3d 100644 --- a/src/components/stepDetails/stepDetails.tsx +++ b/src/components/stepDetails/stepDetails.tsx @@ -44,31 +44,25 @@ export const StepDetails = () => { params.stepId ); - const comments: StepTimelineComment[] = useMemo( - () => - testCase?.data?.comments - .filter((comment) => comment.stepId === step?.data?.id) - .map((comment) => ({ - comment, - type: comment.resolved - ? ActivityType.Comment - : ActivityType.UnsolvedComment, - date: comment.createdAt, - })) ?? [], - [step?.data?.id, testCase?.data?.comments] - ); + const comments: StepTimelineComment[] = + testCase?.data?.comments + .filter((comment) => comment.stepId === step?.data?.id) + .map((comment) => ({ + comment, + type: comment.resolved + ? ActivityType.Comment + : ActivityType.UnsolvedComment, + date: comment.createdAt, + })) ?? []; - const statusChanges: StepTimelineStatusUpdate[] = useMemo( - () => - project - .getStatusChangesByStepId(step?.data?.id ?? "") - .map((statusUpdate) => ({ - statusUpdate, - type: ActivityType.StatusUpdate, - date: statusUpdate.createdAt, - })) ?? [], - [project, step?.data?.id] - ); + const statusChanges: StepTimelineStatusUpdate[] = + project + .getStatusChangesByStepId(step?.data?.id ?? "") + .map((statusUpdate) => ({ + statusUpdate, + type: ActivityType.StatusUpdate, + date: statusUpdate.createdAt, + })) ?? []; const list: StepTimelineItem[] = useMemo(() => { return [...(comments ?? []), ...(statusChanges ?? [])]; diff --git a/src/components/testCasesList/TestCasesList.tsx b/src/components/testCasesList/TestCasesList.tsx index 2b73ae97..091166f6 100644 --- a/src/components/testCasesList/TestCasesList.tsx +++ b/src/components/testCasesList/TestCasesList.tsx @@ -1,4 +1,4 @@ -import { Fragment, useCallback } from "react"; +import { Fragment } from "react"; import classes from "./testCasesList.module.scss"; import { useNavigate, useParams } from "react-router"; import { Collapse, NavLink } from "@mantine/core"; @@ -21,12 +21,9 @@ export const TestCasesList = ({ const { projectId, caseId, testId } = useParams(); const navigate = useNavigate(); const serverName = useServerName(); - const handleClick = useCallback( - (path: string) => () => { - navigate(path); - }, - [navigate] - ); + const handleClick = (path: string) => () => { + navigate(path); + }; return (
{data.map((testCase) => ( diff --git a/src/components/testDetails/TestDetails.tsx b/src/components/testDetails/TestDetails.tsx index b76f1190..f64e9a45 100644 --- a/src/components/testDetails/TestDetails.tsx +++ b/src/components/testDetails/TestDetails.tsx @@ -102,7 +102,7 @@ export function TestDetails() { } }, }), - [navigate, project.data, serverName, test?.data?.id, testCase] + [test?.data?.id] ); const cloneClickHandler = useCallback(() => { diff --git a/src/lib/operators/useProject.ts b/src/lib/operators/useProject.ts index a2423c58..f270ae4c 100644 --- a/src/lib/operators/useProject.ts +++ b/src/lib/operators/useProject.ts @@ -13,13 +13,12 @@ export function useProject(projectId: string | undefined): TUseProject { const { docUrl } = useDocContext(); const [doc, changeDoc] = useDocument(docUrl); - const project: TUseProject["data"] = useMemo( - () => doc?.projects.find((item) => projectId && item.id === projectId), - [doc, projectId] + const project: TUseProject["data"] = doc?.projects.find( + (item) => projectId && item.id === projectId ); - const loading = useMemo(() => !doc, [doc]); - const error = useMemo(() => !!doc && !project, [doc, project]); + const loading = !doc; + const error = !!doc && !project; const getTagsByTestId: TUseProject["getTagsByTestId"] = useCallback( (testId) => { @@ -125,33 +124,29 @@ export function useProject(projectId: string | undefined): TUseProject { [doc?.projects, projectId] ); - const exportJSON: TUseProject["exportJSON"] = useMemo( - () => () => { - const project = doc?.projects.find((p) => p.id === projectId); - - if (project) { - const jsonContent: TJsonExport = { - networkServerUrl: - localStorage.getItem(STORAGE_KEYS.SERVERS_CONF) ?? "", - project, - repository: { - id: docUrl ?? "", - description: doc?.description ?? "", - title: doc?.title ?? "", - }, - }; - - const parsedData = JSON.stringify(jsonContent); - - const slugifiedTitle = slugify(project.title, { - lower: true, - }); + const exportJSON: TUseProject["exportJSON"] = useCallback(() => { + const project = doc?.projects.find((p) => p.id === projectId); + + if (project) { + const jsonContent: TJsonExport = { + networkServerUrl: localStorage.getItem(STORAGE_KEYS.SERVERS_CONF) ?? "", + project, + repository: { + id: docUrl ?? "", + description: doc?.description ?? "", + title: doc?.title ?? "", + }, + }; - downloadFile(parsedData, `ytestbook-export-${slugifiedTitle}.json`); - } - }, - [doc?.description, doc?.projects, doc?.title, docUrl, projectId] - ); + const parsedData = JSON.stringify(jsonContent); + + const slugifiedTitle = slugify(project.title, { + lower: true, + }); + + downloadFile(parsedData, `ytestbook-export-${slugifiedTitle}.json`); + } + }, [doc, docUrl, projectId]); const updateProject: TUseProject["updateProject"] = useCallback( (data) => { diff --git a/src/lib/operators/useStep.ts b/src/lib/operators/useStep.ts index 483f2812..2dda3c24 100644 --- a/src/lib/operators/useStep.ts +++ b/src/lib/operators/useStep.ts @@ -22,8 +22,8 @@ export function useStep( return test?.steps.find((step) => step.id === stepId); }, [doc, projectId, caseId, testId, stepId]); - const loading = useMemo(() => !doc, [doc]); - const error = useMemo(() => !!doc && !step, [doc, step]); + const loading = !doc; + const error = !!doc && !step; if (loading) { return { diff --git a/src/lib/operators/useTest.ts b/src/lib/operators/useTest.ts index 359d49de..a3845422 100644 --- a/src/lib/operators/useTest.ts +++ b/src/lib/operators/useTest.ts @@ -21,8 +21,8 @@ export function useTest( return testCase?.tests.find((test) => test.id === testId); }, [doc, projectId, caseId, testId]); - const loading = useMemo(() => !doc, [doc]); - const error = useMemo(() => !!doc && !test, [doc, test]); + const loading = !doc; + const error = !!doc && !test; const createStep: TUseTest["createStep"] = useCallback( (values) => { diff --git a/src/lib/operators/useTestCase.ts b/src/lib/operators/useTestCase.ts index 79f0af77..d1daea12 100644 --- a/src/lib/operators/useTestCase.ts +++ b/src/lib/operators/useTestCase.ts @@ -21,8 +21,8 @@ export function useTestCase( return p?.testCases.find((item) => item.id === caseId); }, [doc, projectId, caseId]); - const loading = useMemo(() => !doc, [doc]); - const error = useMemo(() => !!doc && !testCase, [doc, testCase]); + const loading = !doc; + const error = !!doc && !testCase; const createTest: TUseTestCase["createTest"] = useCallback( (values) => { diff --git a/vite.config.js b/vite.config.js index 00b42a46..792fb7f4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -5,7 +5,15 @@ import topLevelAwait from "vite-plugin-top-level-await"; import wasm from "vite-plugin-wasm"; export default defineConfig({ - plugins: [topLevelAwait(), wasm(), react()], + plugins: [ + topLevelAwait(), + wasm(), + react({ + babel: { + plugins: ["babel-plugin-react-compiler"], + }, + }), + ], worker: { format: "es", plugins: () => [wasm()],