React-admin: Multi-line notification messages - notifications

How could i make react-admin to show a multi-line notification / error message on the snackbar?
Having the following dataProvider:
export default (type, resource, params) => {
throw new Error(`
Message line 1.
Message line 2.
Message line 3.
`);
};
That shows a single line message when loading a List component:
error notification screenshot

UPDATE 2022:
Since version 4 of react-admin, you can tell the useNotify hook, to use a multi line message passing the multiLine prop: https://marmelab.com/react-admin/useNotify.html#:~:text=multiLine%3A%20Set%20it%20to%20true%20if%20the%20notification%20message%20should%20be%20shown%20in%20more%20than%20one%20line.
End of UPDATE.
Ok, with the help of the docs I manage to do what I wanted.
Defining a custom Layout component to be used by the App component and passing it a custom Notification component.
// ./MyLayout.js
import React from 'react';
import { Layout } from 'react-admin';
import MyNotification from "../MyNotification";
const CustomLayout = props => (
<Layout {...props} notification={MyNotification} />
);
export default CustomLayout;
Then I pass a custom CSS class to the Notification component.
// ./MyNotification.js
import React from 'react';
import {withStyles} from '#material-ui/core/styles';
import {Notification} from 'react-admin';
// Allow multi-line messages to be displayed
const cssMsg = {
snackbarContent: {
whiteSpace: 'pre-wrap'
}
};
const MyNotification = withStyles(cssMsg)(({classes, ...props}) => (
<Notification {...props} className={classes.snackbarContent}/>
));
export default MyNotification;
error notification screenshot multi-line

Related

How to use hooks in custom plugins

I am trying to write a custom plugin for our Docusaurus site. I am able to wire up the custom component, but I cannot use hooks like useState or useEffect. The page crashes saying I'm using an invalid React hook.
I know its possible to use hooks because I see other plugins doing it so I'm sure its a syntax problem somewhere.
Here's my code:
index.ts
import path from 'path'
module.exports = function () {
return {
name: 'docusaurus-theme-myorg-technology',
getThemePath() {
return path.resolve(__dirname, './theme')
}
};
};
theme/index.tsx
import React from 'react'
import {CustomTOC} from './CustomTOC'
const WrappedTOC = (props: any) => {
return (
<CustomTOC {...props} />
);
};
export default WrappedTOC;
theme/CustomTOC.tsx
import React, { useState } from 'react';
import TOC from '#theme-init/TOC';
export default function CustomTOC(props: any) {
//const [tags, setTags] = useState<any[]>([]); <-- if I comment this out the page crashes
return (
<>
<TOC {...props} />
Hello world
</>
);
}
"Invalid hooks call" link to a doc page, that you should read carefully.
Most likely: you are using a different version of React for your component lib that the one Docusaurus uses internally, and it leads to the React lib being used twice at runtime. Make sure the final project will only include one React version. You can for example use the exact same version that the one Docusaurus uses

"Functions are not valid as a React child" error message shows up after adding JavaScript Map function

I added a normal array.prototype.map function to iterate through an array in my code, but keep getting a warning error. I double checked the syntax for the map function and that does not seem to be the issue. I have also tried passing different arrays into the function with different values.
Here is the warning error.
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
And my code:
function App() {
const[items, setItems] =
useState([{toDo: 'vacuum', done: false},
{toDo: 'Do laundry', done: false},
{toDo: 'Walk the dog', done: false}])
return (
<div>
{
(items.map = (item, index) => {
<p>{item}</p>;
})
}
</div>
);
};
This is the error path in the console:
at div
at Home
at Route (http://localhost:3000/static/js/bundle.js:41724:29)
at Switch (http://localhost:3000/static/js/bundle.js:41926:29)
at div
at div
at Router (http://localhost:3000/static/js/bundle.js:41355:30)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:39344:35)
at App
at Router (http://localhost:3000/static/js/bundle.js:41355:30)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:39344:35)
I am wondering if it is at all related to my index.js page.
This is what it currently looks like.
import React from "react";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import reactDom from "react-dom/client";
const root = reactDom.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
Any help would be much appreciated!

Expo app problem loading especific custon font weights

I have created an react-native/typescript app with expo CLI, this generate some base code, inlcuding hooks/useCachedResources to load any resources or data that we need prior to rendering the app, in my case in this hook I load custom fonts(in particular Inter Display Font). I'm experimenting some problems because the app loads only two weights: regular and medium, If I try to use semi-bold or bold this doesnt work and use the san serif font that comes by default.
Additional data:
The fonts path its ok
Expo app doesn't show any error. I have seen in other questions errors such as fontFamily "MyFontFamily" is not a system font and has not been loaded through Font.loadAsync. This is not the case.
Font family name is in the correct format.
I'm using React Native UI Kitten and I load the fonts as they suggest in Advanced Configuration and change some especific styles.
According to some answers The out of the box support for custom fonts on Android is a little limited in React Native. It does not support font weights other than normal and bold. So I tried setting fontWeight: normal or any of the weights but nothing works.
useCachedResources hook
This come by default with expo init my-app.
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect, useState } from 'react';
// Error reporting service
import { logger } from '#utils';
export function useCachedResources(): boolean {
const [isLoadingComplete, setLoadingComplete] = useState(false);
// Load any resources or data that we need prior to rendering the app
useEffect(() => {
async function loadResourcesAndDataAsync() {
try {
await SplashScreen.preventAutoHideAsync();
// Load fonts
await Font.loadAsync({
'inter-display-regular': require('../assets/fonts/InterDisplay-Regular.ttf'),
'inter-display-medium': require('../assets/fonts/InterDisplay-Medium.ttf'),
'inter-display-semibold': require('../assets/fonts/InterDisplay-SemiBold.ttf'),
'inter-display-bold': require('../assets/fonts/InterDisplay-Bold.ttf'),
});
} catch (loadCachedResourcesError) {
logger.log(loadCachedResourcesError);
} finally {
setLoadingComplete(true);
await SplashScreen.hideAsync();
}
}
loadResourcesAndDataAsync();
}, []);
return isLoadingComplete;
}
Consuming the hook in App.tsx
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import useCachedResources from './hooks/useCachedResources';
import Navigation from './navigation';
// again this comes by defautl expo init command
export default function App(): React.ReactElement | null {
const isLoadingComplete = useCachedResources();
if (!isLoadingComplete) {
return null;
}
return (
<SafeAreaProvider>
<Navigation />
<StatusBar />
</SafeAreaProvider>
);
}
mapping.json: specific UI-Kitten configuration to change font style
I can think that the problem comes from here but the thing is, if there was a problem loading the fonts, either expo would have already thrown an error or the other fonts weights(regular/medium) would not load.
{
"strict": {
"text-font-family": "inter-display-regular",
"text-heading-1-font-size": 32,
"text-heading-1-font-weight": "normal",
"text-heading-1-font-family": "inter-display-medium",
"text-paragraph-1-font-size": 16,
"text-paragraph-1-font-weight": "normal",
"text-paragraph-1-font-family": "$text-font-family",
}
}
The problem
I have no idea if the problem comes from expo, ui kitten or if inter font can't be loaded by react native by some other reason.
In your useCachedResources try to remove 'await' keyword from SplashScreen method's:
SplashScreen.preventAutoHideAsync();
SplashScreen.hideAsync();

Is is possible to use a custom notification library in react-admin instead of the built-in notifications? [duplicate]

How could i make react-admin to show a multi-line notification / error message on the snackbar?
Having the following dataProvider:
export default (type, resource, params) => {
throw new Error(`
Message line 1.
Message line 2.
Message line 3.
`);
};
That shows a single line message when loading a List component:
error notification screenshot
UPDATE 2022:
Since version 4 of react-admin, you can tell the useNotify hook, to use a multi line message passing the multiLine prop: https://marmelab.com/react-admin/useNotify.html#:~:text=multiLine%3A%20Set%20it%20to%20true%20if%20the%20notification%20message%20should%20be%20shown%20in%20more%20than%20one%20line.
End of UPDATE.
Ok, with the help of the docs I manage to do what I wanted.
Defining a custom Layout component to be used by the App component and passing it a custom Notification component.
// ./MyLayout.js
import React from 'react';
import { Layout } from 'react-admin';
import MyNotification from "../MyNotification";
const CustomLayout = props => (
<Layout {...props} notification={MyNotification} />
);
export default CustomLayout;
Then I pass a custom CSS class to the Notification component.
// ./MyNotification.js
import React from 'react';
import {withStyles} from '#material-ui/core/styles';
import {Notification} from 'react-admin';
// Allow multi-line messages to be displayed
const cssMsg = {
snackbarContent: {
whiteSpace: 'pre-wrap'
}
};
const MyNotification = withStyles(cssMsg)(({classes, ...props}) => (
<Notification {...props} className={classes.snackbarContent}/>
));
export default MyNotification;
error notification screenshot multi-line

How to not put "use strict" everywhere

I'm trying to write some tests for a React app I've been working on, and I figured I would use Jest since it's mentioned in the React docs.
I'm using Webpack and so far I've installed jest-cli, babel-jest, and I included the following configuration in package.json:
"jest": {
"scriptPreprocessor": "./node_modules/babel-jest",
"unmockedModulePathPatterns": [
"./node_modules/react",
"./node_modules/react-dom"
],
}
So, I'm writing the tests for some file foo.js. This file includes some other module bar.js (i.e. const bar = require('./bar');). Unfortunately, when I run jest I get the following error:
SyntaxError: Block-scoped declarations (let, const, function, class) not yet
supported outside strict mode in file 'js/foo.js'.
So, after some research, I find out I have to include 'use strict'; at the top of foo-test.js. However, for some reason, I still get the same error unless I also include 'use strict'; at the top of foo.js.
So my question is: am I doing something wrong? If not, is there anyway for me to write my tests using Jest without having to write 'use strict'; at the top of all my source files?
It seems to test out basic ES2015 classes with jest, use strict is required, however to test React Components, 'use strict' isn't required. Here's an example
//CheckboxWithLabel.js
import React, {Component} from 'react';
class CheckboxWithLabel extends Component {
constructor(){
super(...arguments);
this.state = {
isChecked: false
};
this.onChange = this.onChange.bind(this);
}
onChange() {
this.setState({
isChecked: !this.state.isChecked
});
}
render() {
return (
<label>
<input type="checkbox"
checked={this.state.isChecked}
onChange={this.onChange} />
{this.state.isChecked ? this.props.labelOn : this.props.labelOff }
</label>
);
}
}
export default CheckboxWithLabel;
//CheckboxWithLabel_tests.js
jest.disableAutomock(); //use this instead of jest.autoMockOff()
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import CheckboxWithLabel from '../source/components/CheckboxWithlabel';
// const CheckboxWithLabel = require('../source/components/CheckboxWithLabel');
describe('CheckboxWithlabel', () => {
const shallowRenderer = TestUtils.createRenderer();
//render a checkbox
const checkbox = TestUtils.renderIntoDocument(
<CheckboxWithLabel labelOn="On" labelOff="Off" />
);
// shallowRenderer.render(<CheckboxWithLabel labelOn="On" labelOff="Off" />)
// const checkbox = shallowRenderer.getRenderOutput();
// it('defaults to unchecked and off label', () => {
// const inputField = checkbox.props.children[0];
// const textNode = checkbox.props.children[1];
// expect(inputField.props.checked).toBe(false);
// expect(textNode).toEqual('Off');
// })
var checkboxNode = ReactDOM.findDOMNode(checkbox);
// let checkboxElement = TestUtils.findRenderedDOMComponentWithTag(checkbox, 'input');
it('defaults to Off label', () => {
expect(checkboxNode.textContent).toEqual('Off');
// expect(checkboxElement.checked).toBe(false);
});
})
Edited: This is not required anymore
Notice the only caveat being that you have to explicitly add a auto_mock_off.js file that simply adds this line (it took me hours to figure this one out)
jest.autoMockOff();
More information can be found on this thread on github Github React Issue #932
That's it! the component testing works perfectly. I've also tried the same example with shallow rendering and it worked perfectly too! Hope this helps!