Upgrade to react-admin v5 (#633)

* bump dependencies
* replace react-query with @tanstack/react-query
* remove darkTheme
* remove obsolete fullWidth
* fix pagination
* fix language for ra.navigation
* fix 'record' is possibly 'undefined'
* add missing @mui/utils
* bump yarn to 4.4.x
This commit is contained in:
Dirk Klimpel 2025-05-09 20:53:41 +02:00 committed by GitHub
parent d5c10b6e02
commit e8e28b5df1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1917 additions and 1789 deletions

File diff suppressed because one or more lines are too long

925
.yarn/releases/yarn-4.4.1.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
yarnPath: .yarn/releases/yarn-4.1.1.cjs
yarnPath: .yarn/releases/yarn-4.4.1.cjs

View File

@ -10,9 +10,10 @@
"type": "git",
"url": "https://github.com/Awesome-Technologies/synapse-admin"
},
"packageManager": "yarn@4.1.1",
"packageManager": "yarn@4.4.1",
"devDependencies": {
"@eslint/js": "^9.7.0",
"@mui/utils": "^6.1.3",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^16.0.0",
@ -51,25 +52,25 @@
"@haxqer/ra-language-chinese": "^4.16.2",
"@mui/icons-material": "^5.16.4",
"@mui/material": "^5.16.4",
"@tanstack/react-query": "^5.59.12",
"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.3",
"ra-i18n-polyglot": "^5.2.3",
"ra-language-english": "^5.2.3",
"ra-language-farsi": "^5.0.0",
"ra-language-french": "^5.2.3",
"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.3",
"react-dom": "^18.3.1",
"react-hook-form": "^7.52.1",
"react-is": "^18.3.1",
"react-query": "^3.39.3",
"react-router": "^6.25.1",
"react-router-dom": "^6.25.1"
"react-router": "^6.28.1",
"react-router-dom": "^6.28.1"
},
"scripts": {
"start": "vite serve",

View File

@ -1,4 +1,6 @@
import { render, screen } from "@testing-library/react";
import fetchMock from "jest-fetch-mock";
fetchMock.enableMocks();
import App from "./App";

View File

@ -53,7 +53,6 @@ const App = () => (
authProvider={authProvider}
dataProvider={dataProvider}
i18nProvider={i18nProvider}
darkTheme={{ palette: { mode: "dark" } }}
>
<CustomRoutes>
<Route path="/import_users" element={<ImportFeature />} />

View File

@ -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 }) => {
<TextInput
source="body"
label="resources.servernotices.fields.body"
fullWidth
multiline
rows="4"
resettable
@ -64,6 +63,10 @@ export const ServerNoticeButton = () => {
const handleDialogOpen = () => setOpen(true);
const handleDialogClose = () => setOpen(false);
if (!record) {
return;
}
const handleSend = (values: Partial<RaRecord>) => {
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 (
<>
<Button label="resources.servernotices.send" onClick={openDialog} disabled={isLoading}>
<Button label="resources.servernotices.send" onClick={openDialog} disabled={isPending}>
<MessageIcon />
</Button>
<ServerNoticeDialog open={open} onClose={closeDialog} onSubmit={sendNotices} />

View File

@ -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 }) => {
<DialogContentText>{translate("delete_media.helper.send")}</DialogContentText>
<SimpleForm toolbar={<DeleteMediaToolbar />} onSubmit={onSubmit}>
<DateTimeInput
fullWidth
source="before_ts"
label="delete_media.fields.before_ts"
defaultValue={0}
parse={dateParser}
/>
<NumberInput
fullWidth
source="size_gt"
label="delete_media.fields.size_gt"
defaultValue={0}
@ -70,7 +68,6 @@ const DeleteMediaDialog = ({ open, onClose, onSubmit }) => {
step={1024}
/>
<BooleanInput
fullWidth
source="keep_profiles"
label="delete_media.fields.keep_profiles"
defaultValue={true}
@ -86,20 +83,18 @@ export const DeleteMediaButton = (props: ButtonProps) => {
const [open, setOpen] = useState(false);
const notify = useNotify();
const dataProvider = useDataProvider<SynapseDataProvider>();
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": {

View File

@ -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",

View File

@ -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: "Адрес домашнего сервера",

View File

@ -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",

View File

@ -217,7 +217,6 @@ const LoginPage = () => {
disabled={loading || !supportPassAuth}
onBlur={handleUsernameChange}
resettable
fullWidth
validate={required()}
/>
</Box>
@ -229,7 +228,6 @@ const LoginPage = () => {
autoComplete="current-password"
disabled={loading || !supportPassAuth}
resettable
fullWidth
validate={required()}
/>
</Box>
@ -242,7 +240,6 @@ const LoginPage = () => {
disabled={loading}
readOnly={allowSingleBaseUrl}
resettable={allowAnyBaseUrl}
fullWidth
validate={[required(), validateBaseUrl]}
>
{allowMultipleBaseUrls &&

View File

@ -25,7 +25,7 @@ import {
useRefresh,
useUnselectAll,
} from "react-admin";
import { useMutation } from "react-query";
import { useMutation } from "@tanstack/react-query";
import AvatarField from "../components/AvatarField";
@ -70,27 +70,25 @@ export const RoomDirectoryBulkPublishButton = (props: ButtonProps) => {
const refresh = useRefresh();
const unselectAllRooms = useUnselectAll("rooms");
const dataProvider = useDataProvider();
const { mutate, isLoading } = useMutation(
() =>
const { mutate, isPending } = useMutation({
mutationFn: () =>
dataProvider.createMany("room_directory", {
ids: selectedIds,
data: {},
}),
{
onSuccess: () => {
notify("resources.room_directory.action.send_success");
unselectAllRooms();
refresh();
},
onError: () =>
notify("resources.room_directory.action.send_failure", {
type: "error",
}),
}
);
onSuccess: () => {
notify("resources.room_directory.action.send_success");
unselectAllRooms();
refresh();
},
onError: () =>
notify("resources.room_directory.action.send_failure", {
type: "error",
}),
});
return (
<Button {...props} label="resources.room_directory.action.create" onClick={mutate} disabled={isLoading}>
<Button {...props} label="resources.room_directory.action.create" onClick={mutate} disabled={isPending}>
<RoomDirectoryIcon />
</Button>
);
@ -102,6 +100,10 @@ export const RoomDirectoryPublishButton = (props: ButtonProps) => {
const refresh = useRefresh();
const [create, { isLoading }] = useCreate();
if (!record) {
return;
}
const handleSend = () => {
create(
"room_directory",

View File

@ -1,7 +1,14 @@
import { stringify } from "query-string";
import { DataProvider, DeleteParams, Identifier, Options, RaRecord, fetchUtils } from "react-admin";
import {
DataProvider,
DeleteParams,
Identifier,
Options,
PaginationPayload,
RaRecord,
SortPayload,
fetchUtils
} from "react-admin";
import storage from "../storage";
// Adds the access token to all requests
@ -492,8 +499,8 @@ const dataProvider: SynapseDataProvider = {
getList: async (resource, params) => {
console.log("getList " + resource);
const { user_id, name, guests, deactivated, locked, search_term, destination, valid } = params.filter;
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const { page, perPage } = params.pagination as PaginationPayload;
const { field, order } = params.sort as SortPayload;
const from = (page - 1) * perPage;
const query = {
from: from,

1716
yarn.lock

File diff suppressed because it is too large Load Diff