mirror of
https://github.com/strapi/strapi.git
synced 2025-07-22 08:26:44 +00:00

* Fix: formatting Signed-off-by: KULDIP PIPALIYA <kuldipem@gmail.com> * Fix: formatting Signed-off-by: KULDIP PIPALIYA <kuldipem@gmail.com> * Enhance: consistance formatting for NOTE Signed-off-by: KULDIP PIPALIYA <kuldipem@gmail.com> * Enhance: consistance formatting for NOTE Signed-off-by: KULDIP PIPALIYA <kuldipem@gmail.com>
286 lines
11 KiB
Markdown
286 lines
11 KiB
Markdown
# Front-end Development
|
|
|
|
Strapi's admin panel and plugins system aim to be an easy and powerful way to create new features.
|
|
|
|
The admin panel is a [React](https://facebook.github.io/react/) application which can embed other React applications. These other React applications are the `admin` parts of each Strapi's plugins.
|
|
|
|
## Environment setup
|
|
|
|
To enable local plugin development, you need to start your application with the front-end development mode activated:
|
|
|
|
```bash
|
|
$ cd my-app
|
|
$ yarn develop --watch-admin
|
|
```
|
|
|
|
## API
|
|
|
|
### Strapi global variable
|
|
|
|
The administration exposes a global variable that is accessible for all the plugins.
|
|
|
|
#### `strapi.backendURL`
|
|
|
|
Retrieve the back-end URL. (e.g. `http://localhost:1337`).
|
|
|
|
#### `strapi.currentLanguage`
|
|
|
|
Retrieve the administration panel default language (e.g. `en-US`)
|
|
|
|
#### `strapi.languages`
|
|
|
|
Array of the administration panel's supported languages. (e.g. `['ar', 'en', 'fr', ...]`).
|
|
|
|
#### `strapi.lockApp()`
|
|
|
|
Display a loader that will prevent the user from interacting with the application.
|
|
|
|
#### `strapi.unlockApp()`
|
|
|
|
Remove the loader so the user can interact with the application
|
|
|
|
#### `strapi.notification`
|
|
|
|
Display a notification (works with i18n message id). Use this command anywhere in your code.
|
|
|
|
```js
|
|
strapi.notification.error('app.notification.error');
|
|
strapi.notification.info('app.notification.info');
|
|
strapi.notification.success('app.notification.success');
|
|
strapi.notification.warning('app.notification.warning');
|
|
```
|
|
|
|
#### `strapi.remoteURL`
|
|
|
|
The administration url (e.g. `http://localhost:4000/admin`).
|
|
|
|
### Main plugin object
|
|
|
|
Each plugin exports all its configurations in an object. This object is located in `my-plugin/admin/src/index.js`
|
|
|
|
Here are its properties:
|
|
|
|
| key | type | Description |
|
|
| ------------------------- | ------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| blockerComponent | node | Props can be either `null` or React node (e.g. `() => <div />`) |
|
|
| blockerComponentProps | object | Props to provide to customise the [blockerComponent](https://github.com/strapi/strapi/blob/58588e10e5d15921b0966e20ce1bc6cde70df5cc/packages/strapi-helper-plugin/lib/src/components/BlockerComponent/index.js#L81-L86) |
|
|
| description | string | Plugin's description retrieved from the package.json |
|
|
| id | string | Id of the plugin from the `package.json` |
|
|
| initializer | node | Refer to the [Initializer documentation](#initializer) |
|
|
| injectedComponents | array | Refer to the [Injected Component documentation](#injected-components) |
|
|
| isReady | boolean | The app will load until this proprety is true |
|
|
| leftMenuLinks | array | Array of links to inject in the menu |
|
|
| mainComponent | node | The plugin's App container, setting it to null will prevent the plugin from being displayed in the menu |
|
|
| name | string | The plugin's name retrieved from the package.json |
|
|
| pluginLogo | file | The plugin's logo |
|
|
| preventComponentRendering | boolean | Whether or not display the plugin's blockerComponent instead of the main component |
|
|
| settings | object | Refer to the [Plugins settings API](./frontend-settings-api.md) |
|
|
| reducers | object | The plugin's redux reducers |
|
|
| trads | object | The plugin's translation files |
|
|
|
|
### Initializer
|
|
|
|
The component is generated by default when you create a new plugin. Use this component to execute some logic when the app is loading. When the logic has been executed this component should emit the `isReady` event so the user can interact with the application.
|
|
|
|
::: tip NOTE
|
|
Below is the Initializer component of the content-type-builder plugin.
|
|
|
|
It checks whether or not the autoreload feature is enabled and depending on this value changes the mainComponent of the plugin.
|
|
:::
|
|
|
|
```js
|
|
/**
|
|
*
|
|
* Initializer
|
|
*
|
|
*/
|
|
|
|
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
|
|
import pluginId from '../../pluginId';
|
|
|
|
class Initializer extends React.PureComponent {
|
|
// eslint-disable-line react/prefer-stateless-function
|
|
componentDidMount() {
|
|
const {
|
|
admin: { autoReload, currentEnvironment },
|
|
} = this.props;
|
|
|
|
let preventComponentRendering;
|
|
let blockerComponentProps;
|
|
|
|
if (currentEnvironment === 'production') {
|
|
preventComponentRendering = true;
|
|
blockerComponentProps = {
|
|
blockerComponentTitle: 'components.ProductionBlocker.header',
|
|
blockerComponentDescription: 'components.ProductionBlocker.description',
|
|
blockerComponentIcon: 'fa-ban',
|
|
blockerComponentContent: 'renderButton',
|
|
};
|
|
} else {
|
|
// Don't render the plugin if the server autoReload is disabled
|
|
preventComponentRendering = !autoReload;
|
|
blockerComponentProps = {
|
|
blockerComponentTitle: 'components.AutoReloadBlocker.header',
|
|
blockerComponentDescription: 'components.AutoReloadBlocker.description',
|
|
blockerComponentIcon: 'fa-refresh',
|
|
blockerComponentContent: 'renderIde',
|
|
};
|
|
}
|
|
|
|
// Prevent the plugin from being rendered if currentEnvironment === PRODUCTION
|
|
this.props.updatePlugin(pluginId, 'preventComponentRendering', preventComponentRendering);
|
|
this.props.updatePlugin(pluginId, 'blockerComponentProps', blockerComponentProps);
|
|
// Emit the event plugin ready
|
|
this.props.updatePlugin(pluginId, 'isReady', true);
|
|
}
|
|
|
|
render() {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Initializer.propTypes = {
|
|
admin: PropTypes.object.isRequired,
|
|
updatePlugin: PropTypes.func.isRequired,
|
|
};
|
|
|
|
export default Initializer;
|
|
```
|
|
|
|
### Injected Components
|
|
|
|
(Coming soon)
|
|
|
|
### Routing
|
|
|
|
The routing is based on the [React Router V5](https://reacttraining.com/react-router/web/guides/philosophy), due to it's implementation each route is declared in the `containers/App/index.js` file.
|
|
|
|
::: tip
|
|
Each route defined in a plugin must be prefixed by the plugin's id.
|
|
:::
|
|
|
|
**Route declaration :**
|
|
|
|
Let's say that you want to create a route `/user` with params `/:id` associated with the container UserPage.
|
|
|
|
The declaration would be as follows :
|
|
|
|
**Path —** `plugins/my-plugin/admin/src/containers/App/index.js`.
|
|
|
|
```js
|
|
import React from 'react';
|
|
import pluginId from '../../pluginId';
|
|
|
|
import UserPage from '../UserPage';
|
|
|
|
// ...
|
|
|
|
class App extends React.Component {
|
|
// ...
|
|
|
|
render() {
|
|
return (
|
|
<div>
|
|
<Switch>
|
|
<Route exact path={`/plugins/${pluginId}/user/:id`} component={UserPage} />
|
|
</Switch>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
// ...
|
|
```
|
|
|
|
### Styling
|
|
|
|
The administration panel uses [styled-components](https://styled-components.com/) for writing css.
|
|
|
|
### i18n
|
|
|
|
[React Intl](https://github.com/yahoo/react-intl) provides React components and an API to format dates, numbers, and strings, including pluralization and handling translations.
|
|
|
|
**Usage**
|
|
|
|
We recommend to set all your components text inside the translations folder.
|
|
|
|
The example below shows how to use i18n inside your plugin.
|
|
|
|
**Define all your ids with the associated message:**
|
|
|
|
**Path —** `./plugins/my-plugin/admin/src/translations/en.json`.
|
|
|
|
```json
|
|
{
|
|
"notification.error.message": "An error occurred"
|
|
}
|
|
```
|
|
|
|
**Path —** `./plugins/my-plugin/admin/src/translations/fr.json`
|
|
|
|
```json
|
|
{
|
|
"notification.error.message": "Une erreur est survenue"
|
|
}
|
|
```
|
|
|
|
**Usage inside a component**
|
|
|
|
**Path —** `./plugins/my-plugin/admin/src/components/Foo/index.js`.
|
|
|
|
```js
|
|
import { FormattedMessage } from 'react-intl';
|
|
import SomeOtherComponent from 'components/SomeOtherComponent';
|
|
|
|
const Foo = props => (
|
|
<div className={styles.foo}>
|
|
<FormattedMessage id="my-plugin.notification.error.message" />
|
|
<SomeOtherComponent {...props} />
|
|
</div>
|
|
);
|
|
|
|
export default Foo;
|
|
```
|
|
|
|
See [the documentation](https://github.com/yahoo/react-intl/wiki/Components#formattedmessage) for more extensive usage.
|
|
|
|
### Global context
|
|
|
|
All plugins are wrapped inside the `GlobalContextProvider`, in this object you will have access to all plugins object as well as other utilities.
|
|
|
|
Usage:
|
|
|
|
**Inside a functional component:**
|
|
|
|
```js
|
|
import React from 'react';
|
|
import { useGlobalContext } from 'strapi-helper-plugin';
|
|
|
|
const Foo = () => {
|
|
const globalContext = useGlobalContext();
|
|
|
|
console.log(globalContext);
|
|
|
|
return <div>Foo</div>;
|
|
};
|
|
```
|
|
|
|
**Inside a class component:**
|
|
|
|
```js
|
|
import React from 'react';
|
|
import { GlobalContext } from 'strapi-helper-plugin';
|
|
|
|
class Foo extends React.Component {
|
|
static contextType = GlobalContext;
|
|
|
|
render() {
|
|
console.log(this.context);
|
|
|
|
return <div>Foo</div>;
|
|
}
|
|
}
|
|
```
|