react-admin icon indicating copy to clipboard operation
react-admin copied to clipboard

Auto translate resource fields does not work when using an add/edit form inside a Dialog

Open Bossieh opened this issue 4 years ago • 6 comments

I have two ways to edit an alarm, one via a dedicated list with default create/edit forms, and one via a list inside the tab of a related parent record.

The fields in the default create/edit forms are translated properly, but not in the form inside the Dialog.

I have added a short video to demonstrate what I mean. https://user-images.githubusercontent.com/3696955/120433238-4884f980-c37b-11eb-81af-ea5db4d4c50f.mp4

Edit: Saving form when hitting enter inside a TextField does not work as well, possibly related? /Edit

I am using:

  • "react-dom": "17.0.2"
  • "react": "17.0.2"
  • "react-admin": "3.15.2"
  • "ra-i18n-polyglot": "3.15.2"

The code for the "Alarms" tab:

import {
    Button, Datagrid, ExportButton, FormWithRedirect, List, required, SaveButton, TextField, TextInput, TopToolbar, 
    TranslatableFields, useCreate, useListContext, useNotify, useRefresh,
} from "react-admin";
import {useState} from "react";
import AddIcon from "@material-ui/icons/Add";
import {Dialog, DialogActions, DialogContent, DialogTitle} from "@material-ui/core";
import IconCancel from "@material-ui/icons/Cancel";
import locales from "../../../locales.js";

const AddAlarmDialog = ({machineTypeId, open = false, onClose, onSuccess}) => {
    const [create, { loading }] = useCreate('machine-files');
    const notify = useNotify();

    const handleSubmit = async values => {
        create(
            {
                payload: {
                    data: {
                        ...values,
                        machineTypeId: machineTypeId
                    }
                }
            },
            {
                onSuccess: () => {
                    onSuccess();
                },
                onFailure: (error) => {
                    notify(error.message, 'error');
                }
            }
        );
    };

    return (
        <Dialog
            open={open}
            onClose={onClose}
            fullWidth
            maxWidth="md"
        >
            <DialogTitle>Alarm toevoegen</DialogTitle>
            <FormWithRedirect
                resource="machine-alarms"
                save={handleSubmit}
                render={({
                             handleSubmitWithRedirect,
                             pristine,
                             saving
                         }) => (
                    <>
                        <DialogContent>
                            <TextInput
                                source="code"
                                validate={[required()]}
                            />
                            <TranslatableFields locales={locales}>
                                <TextInput multiline fullWidth source="cause" />
                                <TextInput multiline fullWidth source="description" />
                                <TextInput multiline fullWidth source="solution" />
                            </TranslatableFields>
                        </DialogContent>
                        <DialogActions>
                            <Button
                                label="ra.action.cancel"
                                onClick={onClose}
                                disabled={loading}
                            >
                                <IconCancel />
                            </Button>
                            <SaveButton
                                handleSubmitWithRedirect={
                                    handleSubmitWithRedirect
                                }
                                pristine={pristine}
                                saving={saving}
                                disabled={loading}
                            />
                        </DialogActions>
                    </>
                )}
            />
        </Dialog>
    )
}

const ListActions = ({props, machineTypeId}) => {
    const [showAddAlarmDialog, setShowAlarmDialog] = useState(false);
    const refresh = useRefresh();

    const {
        maxResults,
    } = props;

    const {
        currentSort,
        resource,
        filterValues,
        total,
    } = useListContext();

    return (
        <>
            <TopToolbar>
                <Button
                    size="small"
                    label="Toevoegen"
                    onClick={() => {
                        setShowAlarmDialog(true);
                    }}
                >
                    <AddIcon />
                </Button>
                <ExportButton
                    disabled={total === 0}
                    resource={resource}
                    sort={currentSort}
                    filterValues={filterValues}
                    maxResults={maxResults}
                />
            </TopToolbar>
            <AddAlarmDialog
                props={props}
                open={showAddAlarmDialog}
                onClose={() => {
                    setShowAlarmDialog(false);
                }}
                onSuccess={() => {
                    setShowAlarmDialog(false);
                    refresh(); // todo refresh only alarm list and not everything
                }}
                machineTypeId={machineTypeId}
            />
        </>
    )
}

const TabAlarms = ({props, machineTypeId}) => {
    return (

        <List
            {...props}
            style={{
                width: '100%'
            }}
            resource="machine-alarms"
            filter={{
                machineTypeId: machineTypeId
            }}
            perPage={25}
            title=" "
            actions={<ListActions
                props={props}
                machineTypeId={props.id}
            />}
            empty={false}
        >
            <Datagrid>
                <TextField
                    source="id"
                />
                <TextField
                    source="cause.nl"
                />
                <TextField
                    source="description.nl"
                />
                <TextField
                    source="solution.nl"
                />
            </Datagrid>
        </List>
    )
}

export default TabAlarms;

Bossieh avatar Jun 02 '21 06:06 Bossieh

Thanks for reporting this. Please provide a sample application showing the issue by forking the following CodeSandbox (https://codesandbox.io/s/github/marmelab/react-admin/tree/master/examples/simple).

djhi avatar Jun 02 '21 08:06 djhi

Translation also fails when I am using an Input inside a FormDataConsumer

For example:

<FormDataConsumer>
    {({ formData, ...rest }) => (
        <>
            {formData.userTypeId === 2 &&
            <BooleanInput
                source="receivesSystemEmails"
                helperText="resources.users.fieldHelperTexts.receivesSystemEmails" // <<<<<<<< fails here
            />
            }
        </>
    )}
</FormDataConsumer>

<BooleanInput
    source="receivesSystemEmails"
    helperText="resources.users.fieldHelperTexts.receivesSystemEmails" // <<<<<<<<< works here
/>

Bossieh avatar Aug 17 '21 09:08 Bossieh

@djhi Also I am using the Enterprice edition, could you please fix this as soon as possible?

Bossieh avatar Aug 17 '21 10:08 Bossieh

Hi Lucus,

I can't reproduce the problem you describe (failed translation inside a FormDataConsumer) with the simple example (see https://codesandbox.io/s/inspiring-bartik-1u4h9?file=/src/posts/PostEdit.tsx). There must be something else in your code that causes the bug. It may be caused by a duplicate ra-core or ra-ui-material-ui package in your yarn.lock.

Can you please try and reproduce your issue based on the URL above?

Cheers,

François

fzaninotto avatar Aug 23 '21 08:08 fzaninotto

Having the same issue when I use an custom Edit form made with those instructions:

https://github.com/marmelab/react-admin/blob/e1ad7e6485b39a341d4d45e93b489fde5f333eea/docs/CreateEdit.md#usecreatecontroller

The translations worked fine in the old style Edit form.

I have no experience with typescript nor with codesandbox.

If you can provide me a sandbox based on JavaScript I can try to reproduce the problem there.

Some additional info:

package.json:

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@date-io/date-fns": "1.3.13",
    "@material-ui/core": "4.12.3",
    "@material-ui/data-grid": "4.0.0-alpha.31",
    "@material-ui/icons": "4.11.2",
    "@material-ui/pickers": "3.3.10",
    "@material-ui/styles": "4.11.4",
    "@react-admin/ra-navigation": "2.3.5",
    "@react-admin/ra-preferences": "1.4.0",
    "@testing-library/jest-dom": "5.12.0",
    "@testing-library/react": "11.2.6",
    "@testing-library/user-event": "12.8.3",
    "base-64": "1.0.0",
    "chart.js": "3.5.1",
    "chokidar": "3.5.2",
    "date-fns": "2.22.1",
    "iframe-resizer": "4.3.2",
    "inflection": "1.13.1",
    "js-file-downloader": "1.1.19",
    "jwt-decode": "3.1.2",
    "lodash": "4.17.21",
    "luxon": "2.0.2",
    "nice-bytes": "1.1.0",
    "papaparse": "5.3.1",
    "ra-data-simple-rest": "3.13.4",
    "ra-i18n-polyglot": "3.18.3",
    "ra-language-dutch": "3.17.2",
    "ra-language-english": "3.18.3",
    "react": "17.0.2",
    "react-admin": "3.18.3",
    "react-admin-import-csv": "1.0.19",
    "react-chartjs-2": "3.0.4",
    "react-dom": "17.0.2",
    "react-dropzone": "11.3.2",
    "react-final-form": "6.5.3",
    "react-final-form-listeners": "1.0.3",
    "react-icons": "4.3.1",
    "react-markdown": "6.0.2",
    "react-router-dom": "5.3.0",
    "react-scripts": "4.0.3",
    "remark-gfm": "1.0.0",
    "throttle-debounce": "3.0.1",
    "web-vitals": "1.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

App.js:

import {fetchUtils, Resource} from "react-admin";
import simpleRestProvider from 'ra-data-simple-rest'; // cheers guys! <3
import {Admin} from 'react-admin';
import layout from "./layout/index.js";
import {MuiPickersUtilsProvider} from '@material-ui/pickers';
import DateFnsUtils from '@date-io/date-fns';
import {ShowAppVersionInfoDialogContextProvider} from "./contexts/show-app-version-info-dialog";

import {authProvider} from "./auth/provider";
import {Dashboard} from "./dashboard";
import customRoutes from "./custom-routes/index";

import dutchMessages from 'ra-language-dutch';
import englishMessages from 'ra-language-english';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import nlLocale from "date-fns/locale/nl";
import dutchTranslations from "./i18n/nl";
import englishTranslations from "./i18n/en";

const httpClient = (url, options = {}) => {
    if (!options.headers) {
        options.headers = new Headers({ Accept: 'application/json' });
    }
    if (localStorage.getItem("apiAccessToken") !== null) {
        options.headers.set('Authorization', `Bearer ${localStorage.getItem("apiAccessToken")}`);
    }
    return fetchUtils.fetchJson(url, options);
};
const dataProvider = simpleRestProvider(process.env.REACT_APP_DATA_BASE_URL + '/admin-api/simple-rest', httpClient);

const messages = {
    'nl': {...dutchMessages, ...dutchTranslations},
    'en': {...englishMessages, ...englishTranslations},
};

const i18nProvider = polyglotI18nProvider((locale) => {
    return messages[locale];
}, 'nl');

const App = () => {
    return (
<>
            <MuiPickersUtilsProvider
                utils={DateFnsUtils}
                locale={nlLocale}
            >
                <ShowAppVersionInfoDialogContextProvider>
                    <Admin
                        i18nProvider={i18nProvider}
                        dataProvider={dataProvider}
                        authProvider={authProvider}
                        dashboard={Dashboard}
                        layout={layout}
                        // loginPage={Login}
                        customRoutes={customRoutes}
                        //theme={theme}
                        title="Kletec Admin panel"
                    >
                        ...
                    </Admin>
                </ShowAppVersionInfoDialogContextProvider>
            </MuiPickersUtilsProvider>
        </>
    )
};

export default App;

Bossieh avatar Oct 14 '21 12:10 Bossieh

@fzaninotto @djhi can you please take another look at this?

Bossieh avatar Oct 29 '21 07:10 Bossieh

With the release of react-admin v5, react-admin v3 has reached its end of life. We won't fix bugs or make any new release on the 3.x branch. We recommend that you switch to a more recent version of react-admin.

So I'm closing this issue as we won't fix it.

fzaninotto avatar Jul 02 '24 08:07 fzaninotto