diff --git a/.vscode/settings.json b/.vscode/settings.json index b7e02b5..497ca10 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,6 @@ }, "eslint.nodePath": ".yarn/sdks", "prettier.prettierPath": ".yarn/sdks/prettier/index.cjs", - "typescript.tsdk": ".yarn/sdks/typescript/lib", + "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true } diff --git a/.yarnrc.yml b/.yarnrc.yml deleted file mode 100644 index e65419a..0000000 --- a/.yarnrc.yml +++ /dev/null @@ -1 +0,0 @@ -yarnPath: .yarn/releases/yarn-4.1.1.cjs diff --git a/README.md b/README.md index a0c1be2..856f525 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ The following changes are already implemented: * [Fix required fields check on Bulk registration CSV upload](https://github.com/etkecc/synapse-admin/pull/32) * [Fix requests with invalid MXIDs on Bulk registration](https://github.com/etkecc/synapse-admin/pull/33) * [Expose user avatar URL field in the UI](https://github.com/etkecc/synapse-admin/pull/27) +* [Upgrade react-admin to v5](https://github.com/etkecc/synapse-admin/pull/40) _the list will be updated as new changes are added_ diff --git a/package.json b/package.json index 06d81b5..371a46d 100644 --- a/package.json +++ b/package.json @@ -10,21 +10,20 @@ "type": "git", "url": "https://github.com/etkecc/synapse-admin" }, - "packageManager": "yarn@4.1.1", "devDependencies": { "@eslint/js": "^9.7.0", "@testing-library/dom": "^10.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^16.0.0", "@testing-library/user-event": "^14.5.2", - "@types/jest": "^29.5.12", + "@types/jest": "^29.5.13", "@types/lodash": "^4.17.7", "@types/node": "^20.14.12", "@types/papaparse": "^5.3.14", "@types/react": "^18.3.3", "@typescript-eslint/eslint-plugin": "^7.16.1", "@typescript-eslint/parser": "^7.16.1", - "@vitejs/plugin-react": "^4.0.0", + "@vitejs/plugin-react": "^4.3.1", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.29.1", @@ -37,11 +36,11 @@ "jest-fetch-mock": "^3.0.3", "prettier": "^3.3.3", "react-test-renderer": "^18.3.1", - "ts-jest": "^29.2.3", + "ts-jest": "^29.2.5", "ts-node": "^10.9.2", "typescript": "^5.4.5", "typescript-eslint": "^7.16.1", - "vite": "^5.3.4", + "vite": "^5.4.6", "vite-plugin-version-mark": "^0.1.0" }, "dependencies": { @@ -49,27 +48,26 @@ "@emotion/styled": "^11.13.0", "@haleos/ra-language-german": "^1.0.0", "@haxqer/ra-language-chinese": "^4.16.2", - "@mui/icons-material": "^5.16.4", - "@mui/material": "^5.16.4", + "@mui/icons-material": "^6.1.1", + "@mui/material": "^6.1.1", + "@tanstack/react-query": "^5.56.2", "history": "^5.3.0", "lodash": "^4.17.21", "papaparse": "^5.4.1", - "query-string": "^7.1.3", - "ra-core": "^4.16.20", - "ra-i18n-polyglot": "^4.16.20", - "ra-language-english": "^4.16.20", - "ra-language-farsi": "^4.2.0", - "ra-language-french": "^4.16.20", + "ra-core": "^5.2.0", + "ra-i18n-polyglot": "^5.2.0", + "ra-language-english": "^5.2.0", + "ra-language-farsi": "^5.0.0", + "ra-language-french": "^5.2.0", "ra-language-italian": "^3.13.1", "ra-language-russian": "^4.14.2", "react": "^18.3.1", - "react-admin": "^4.16.20", + "react-admin": "^5.2.0", "react-dom": "^18.3.1", - "react-hook-form": "^7.52.1", + "react-hook-form": "^7.53.0", "react-is": "^18.3.1", - "react-query": "^3.39.3", - "react-router": "^6.25.1", - "react-router-dom": "^6.25.1" + "react-router": "^6.26.2", + "react-router-dom": "^6.26.2" }, "scripts": { "start": "vite serve", diff --git a/src/App.test.tsx b/src/App.test.tsx index 3a82f7a..3da4e42 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,4 +1,6 @@ -import { render, screen } from "@testing-library/react"; +import { render, screen, waitFor } from "@testing-library/react"; +import fetchMock from "jest-fetch-mock"; +fetchMock.enableMocks(); import App from "./App"; @@ -7,4 +9,4 @@ describe("App", () => { render(); await screen.findAllByText("Welcome to Synapse-admin"); }); -}); +}); \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 91bfc12..5e01fec 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -53,7 +53,6 @@ const App = () => ( authProvider={authProvider} dataProvider={dataProvider} i18nProvider={i18nProvider} - darkTheme={{ palette: { mode: "dark" } }} > } /> diff --git a/src/components/DeleteRoomButton.tsx b/src/components/DeleteRoomButton.tsx index e21c2f2..83a9a72 100644 --- a/src/components/DeleteRoomButton.tsx +++ b/src/components/DeleteRoomButton.tsx @@ -74,7 +74,6 @@ const DeleteRoomButton: React.FC = (props) => { {translate(props.confirmContent)} ) => setBlock(event.target.checked)} diff --git a/src/components/ServerNotices.tsx b/src/components/ServerNotices.tsx index f269a7f..a929835 100644 --- a/src/components/ServerNotices.tsx +++ b/src/components/ServerNotices.tsx @@ -20,7 +20,7 @@ import { useTranslate, useUnselectAll, } from "react-admin"; -import { useMutation } from "react-query"; +import { useMutation } from "@tanstack/react-query"; const ServerNoticeDialog = ({ open, onClose, onSubmit }) => { const translate = useTranslate(); @@ -43,7 +43,6 @@ const ServerNoticeDialog = ({ open, onClose, onSubmit }) => { { const handleDialogOpen = () => setOpen(true); const handleDialogClose = () => setOpen(false); + if (!record) { + return null; + } + const handleSend = (values: Partial) => { create( "servernotices", @@ -100,28 +103,26 @@ export const ServerNoticeBulkButton = () => { const unselectAllUsers = useUnselectAll("users"); const dataProvider = useDataProvider(); - const { mutate: sendNotices, isLoading } = useMutation( - data => + const { mutate: sendNotices, isPending } = useMutation({ + mutationFn: (data) => dataProvider.createMany("servernotices", { ids: selectedIds, data: data, }), - { - onSuccess: () => { - notify("resources.servernotices.action.send_success"); - unselectAllUsers(); - closeDialog(); - }, - onError: () => - notify("resources.servernotices.action.send_failure", { - type: "error", - }), - } - ); + onSuccess: () => { + notify("resources.servernotices.action.send_success"); + unselectAllUsers(); + closeDialog(); + }, + onError: () => + notify("resources.servernotices.action.send_failure", { + type: "error", + }), + }); return ( <> - diff --git a/src/components/media.tsx b/src/components/media.tsx index 772d234..d147477 100644 --- a/src/components/media.tsx +++ b/src/components/media.tsx @@ -28,7 +28,7 @@ import { useRefresh, useTranslate, } from "react-admin"; -import { useMutation } from "react-query"; +import { useMutation } from "@tanstack/react-query"; import { Link } from "react-router-dom"; import { dateParser } from "./date"; @@ -55,14 +55,12 @@ const DeleteMediaDialog = ({ open, onClose, onSubmit }) => { {translate("delete_media.helper.send")} } onSubmit={onSubmit}> { step={1024} /> { const [open, setOpen] = useState(false); const notify = useNotify(); const dataProvider = useDataProvider(); - const { mutate: deleteMedia, isLoading } = useMutation( - (values: DeleteMediaParams) => dataProvider.deleteMedia(values), - { - onSuccess: () => { - notify("delete_media.action.send_success"); - closeDialog(); - }, - onError: () => { - notify("delete_media.action.send_failure", { - type: "error", - }); - }, - } - ); + const { mutate: deleteMedia, isPending } = useMutation({ + mutationFn: (values: DeleteMediaParams) => dataProvider.deleteMedia(values), + onSuccess: () => { + notify("delete_media.action.send_success"); + closeDialog(); + }, + onError: () => { + notify("delete_media.action.send_failure", { + type: "error", + }); + }, + }); const openDialog = () => setOpen(true); const closeDialog = () => setOpen(false); @@ -110,7 +105,7 @@ export const DeleteMediaButton = (props: ButtonProps) => { {...props} label="delete_media.action.send" onClick={openDialog} - disabled={isLoading} + disabled={isPending} sx={{ color: theme.palette.error.main, "&:hover": { diff --git a/src/i18n/de.ts b/src/i18n/de.ts index a6d9c73..4661eeb 100644 --- a/src/i18n/de.ts +++ b/src/i18n/de.ts @@ -4,6 +4,14 @@ import { SynapseTranslationMessages } from "."; const de: SynapseTranslationMessages = { ...formalGermanMessages, + ra: { + ...formalGermanMessages.ra, + navigation: { + ...formalGermanMessages.ra.navigation, + no_filtered_results: "Keine Ergebnisse", + clear_filters: "Alle Filter entfernen", + }, + }, synapseadmin: { auth: { base_url: "Heimserver URL", diff --git a/src/i18n/ru.ts b/src/i18n/ru.ts index cc26253..1bd4056 100644 --- a/src/i18n/ru.ts +++ b/src/i18n/ru.ts @@ -4,6 +4,14 @@ import { SynapseTranslationMessages } from "."; const ru: SynapseTranslationMessages = { ...russianMessages, + ra: { + ...russianMessages.ra, + navigation: { + ...russianMessages.ra.navigation, + no_filtered_results: "Нет результатов", + clear_filters: "Все фильтры сбросить", + }, + }, synapseadmin: { auth: { base_url: "Адрес домашнего сервера", diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index 5936830..75caeba 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -4,6 +4,14 @@ import { SynapseTranslationMessages } from "."; const zh: SynapseTranslationMessages = { ...chineseMessages, + ra: { + ...chineseMessages.ra, + navigation: { + ...chineseMessages.ra.navigation, + no_filtered_results: "没有结果", + clear_filters: "清除所有过滤器", + }, + }, synapseadmin: { auth: { base_url: "服务器 URL", diff --git a/src/pages/LoginPage.test.tsx b/src/pages/LoginPage.test.tsx index f8abf17..225d13c 100644 --- a/src/pages/LoginPage.test.tsx +++ b/src/pages/LoginPage.test.tsx @@ -8,14 +8,17 @@ import { AppContext } from "../AppContext"; import englishMessages from "../i18n/en"; const i18nProvider = polyglotI18nProvider(() => englishMessages, "en", [{ locale: "en", name: "English" }]); +import { act } from "@testing-library/react"; describe("LoginForm", () => { - it("renders with no restriction to homeserver", () => { - render( - - - - ); + it("renders with no restriction to homeserver", async () => { + await act(async () => { + render( + + + + ); + }); screen.getByText(englishMessages.synapseadmin.auth.welcome); screen.getByRole("combobox", { name: "" }); diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx index a2e6cfa..9ffafd9 100644 --- a/src/pages/LoginPage.tsx +++ b/src/pages/LoginPage.tsx @@ -222,7 +222,6 @@ const LoginPage = () => { disabled={loading || !supportPassAuth} onBlur={handleUsernameChange} resettable - fullWidth validate={required()} /> @@ -234,7 +233,6 @@ const LoginPage = () => { autoComplete="current-password" disabled={loading || !supportPassAuth} resettable - fullWidth validate={required()} /> @@ -247,7 +245,6 @@ const LoginPage = () => { disabled={loading} readOnly={allowSingleBaseUrl} resettable={allowAnyBaseUrl} - fullWidth validate={[required(), validateBaseUrl]} > {allowMultipleBaseUrls && @@ -280,9 +277,9 @@ const LoginPage = () => { {translate("synapseadmin.auth.welcome")}