diff --git a/vuepress/docs/.vuepress/next.js b/vuepress/docs/.vuepress/next.js
index a74f4b79ea..01ed0c80f1 100644
--- a/vuepress/docs/.vuepress/next.js
+++ b/vuepress/docs/.vuepress/next.js
@@ -360,8 +360,7 @@ module.exports = {
path + 'compose/content-attributes.md',
path + 'compose/content-templates-tutorial.md',
path + 'compose/digital-assets-tutorial.md',
- path + 'compose/creating-protected-resources.md',
- path + 'compose/extend-app-builder.md'
+ path + 'compose/creating-protected-resources.md'
]
},
{
diff --git a/vuepress/docs/next/docs/reference/deployment-structure.md b/vuepress/docs/next/docs/reference/deployment-structure.md
index d643e5d054..d59b726097 100644
--- a/vuepress/docs/next/docs/reference/deployment-structure.md
+++ b/vuepress/docs/next/docs/reference/deployment-structure.md
@@ -72,11 +72,9 @@ information about Entando bundles deployed to the Entando Component Repository (
* DockerHub:
#### Customization
-The _app-builder_ is built to be customized and will be customized as part of many Entando implementations.
-The _app-builder_ can be customized at runtime via micro frontends
-[widget configuration](../../tutorials/create/mfe/widget-configuration.md). The _app-builder_ can also be
-customized via the integration of custom modules that are added at
-[build time](../../tutorials/compose/extend-app-builder.md).
+The _app-builder_ is customized as part of many Entando implementations.
+It can be customized at runtime via micro frontends
+[widget configuration](../../tutorials/create/mfe/widget-configuration.md).
## component-manager
The _component-manager_ provides the link between the entando-de-app (or your custom core instance) and the
diff --git a/vuepress/docs/next/tutorials/compose/extend-app-builder.md b/vuepress/docs/next/tutorials/compose/extend-app-builder.md
deleted file mode 100644
index 70dc29fa0b..0000000000
--- a/vuepress/docs/next/tutorials/compose/extend-app-builder.md
+++ /dev/null
@@ -1,1273 +0,0 @@
-# Tutorial: Extending the App Builder
-
-Apps for the Entando App Builder are developed as standalone
-applications which can be run using `npm start` in standalone mode.
-
-Each application should be deployed in npm using the `@entando`
-namespace and will export into their dist folder several items used by
-the App Builder when integrating it into the full application.
-
-## Creating a Basic Application
-
-To create a basic application, use the [entando
-fpg]() running the
-`npx @entando/fpg ab-app ` command.
-
-**the `appName` should only contain alphanumeric characters and
-underscores, and should begin with a letter.**
-
-This will create inside the working directory, a boilerplate app-builder
-app in a directory named `` argument.
-
-i.e.
-
-using the command `npm @entando/fpg ab-app testing` inside your home
-directory, a directory named `testing` will be created containing the
-app.
-
-All dependencies will already be installed allowing you to `cd` inside
-the project directory and run `npm start` to start the app running.
-
-## Understanding the Stand Alone Environment
-
-Each app for the App Builder, can run in both a stand alone mode and an
-integrated mode. Using `npm start` will use standalone mode.
-
-In this environment you’ll be looking at the user interface of the app
-inside a default page. This page, which includes a default menu, will
-not be exported and therefore can be customized.
-
-To better understand which elements and components are being exported to
-App Builder, it is best to understand the anatomy of the app.
-
-# Exports
-
-Each app will have a `babel.js` export file similar to:
-
-```js
- import menu from 'ui/common/LinkMenu';
- import { cms as state } from 'state/rootReducer';
- import { routes, routesDir } from 'ui/App';
- import en from 'locales/en';
- import it from 'locales/it';
-
- const testing = {
- id: 'testing',
- menu,
- state,
- routes,
- routesDir,
- locales: {
- en,
- it,
- },
- };
-
- export default testing;
-```
-
-# id: is the app id.
-
-This parameter is used by App Builder to differentiate all integrated
-apps.
-
-# menu: is a React component containing all the menu elements.
-
-These elements are used inside the standalone environment and inside the
-integrated environment as a second level menu. The boilerplate app
-contains a basic menu.
-
-```js
- import React from 'react';
- import { LinkMenuItem } from '@entando/menu';
- import { FormattedMessage } from 'react-intl';
-
- const LinkMenu = () => (
- <>
- }
- to='/use/const/here/imported/from/routes'
- />
- >
- );
-
- export default LinkMenu;
-```
-
-## Customizing the Menu
-
-For this exercise, we will create two links inside the menu. The first
-will link to a page listing all the users inside the entando instance.
-The second will list all the existing page templates inside the Entando
-instance.
-
-For this example we’re using existing APIs from the Entando core just
-for simplicity, you can instead call any API or data source.
-
-In your app project, open `src/ui/common/LinkMenu.js` and update the
-const to the code below.
-
-```js
- const LinkMenu = () => (
- <>
- }
- to='/use/const/here/imported/from/routes'
- />
- }
- to='/use/const/here/imported/from/routes'
- />
- >
- );
-```
-
-it is important that both the `` id property and the
-\`\\`properties inside label have the correct values
-assigned, i.e.:
-
-the LinkMenuItem id will be **menu-userList** while the FormattedMessage
-id will be **testing.menu.userList** and the defaultMessage will be
-**User List**.
-
-# locales
-
-The locales files are objects that contain all of the i18n locales of
-the app.
-
-By default the boilerplate contains both the english and italian i18n
-files.
-
-In your app project in `src/locales/en.js` and `src/locales/it.js` you
-can see your labels.
-
-```js
- export default {
- locale: 'en',
- messages: {
- 'testing.title': '',
- 'testing.label.errors': '',
- 'testing.label.cancel': '',
- 'testing.chooseAnOption': '',
- 'testing.tip': '',
- 'testing.new': '',
- 'testing.save': '',
- 'testing.saveAndApprove': '',
- 'testing.unpublish': '',
- 'testing.setContentAs': '',
- 'testing.cancel': '',
- 'testing.saveAndContinue': '',
- 'testing.stickySave.status': '',
- 'testing.stickySave.lastAutoSave': '',
- },
- };
-```
-
-While running in standalone mode the boilerplate does not offer a way
-for the user pick a locale, but both will be loaded inside app-builder
-and will be consumed as intended by it, using the correct one based on
-the user-picked language.
-
-It is of course possible to change the standalone app to give the user
-the option to choose the locale in here as well, but this is not
-something will be covering in this tutorial.
-
-## Customizing the menu labels
-
-To customize the existing menu labels, we’ll add the new label ids
-inside both the english and Italian locale files:
-
-> **Note**
->
-> If you named your app something besides `testing` you’ll need to fix
-> these tags to match the name of your app.
-
-```js
- ...
- messages: {
- ...
- 'testing.menu.userList': 'List of Users',
- 'testing.menu.pageModelList': 'Page Models',
- ...
- },
- ...
-```
-
-The key in the messages object matches the id of the
-\`\\`component we placed inside the menu, while its
-value is the actual string that will be displayed depending on the
-currently active language.
-
-# Routes and RoutesDir
-
-Both of these elements are imported from `src/ui/App.js`. The first one
-is a collection of actual `` components, and the second one is an
-object containing each route data, i.e.:
-
-```js
- export const routesDir = [
- {
- path: ROUTE_TESTING,
- component: <>app component>,
- },
- ];
-```
-
-The constant `ROUTE_TESTING` is imported from `src/app-init/routes.js`
-
-## Customizing the Routes
-
-Next we will create the two routes for the two links we have created by
-creating first the two constants needed.
-
-In your IDE open `src/app-init/routes.js`
-
-```js
- export const ROUTE_TESTING = '/testing';
- export const ROUTE_USER_LIST = '/testing/user-list';
- export const ROUTE_PAGE_MODELS = '/testing/page-models';
-```
-
-> **Note**
->
-> Change the value of `testing` to what you selected for the name of
-> your App extension.
-
-The value of each constant will be the path of the route. It is
-important that each route is a subroute of the id of the app itself,
-otherwise this may cause name collision when running inside the
-integrated environment of app-builder.
-
-Both routes are next imported inside `App.js`:
-
-Update the imports with your new ROUTE tags.
-
-```js
- import {
- ROUTE_TESTING,
- ROUTE_USER_LIST,
- ROUTE_PAGE_MODELS,
- } from 'app-init/routes';
-```
-
-and then add to the `routesDir` constant:
-
-```js
- export const routesDir = [
- {
- path: ROUTE_TESTING,
- component: <>app component>,
- },
- {
- path: ROUTE_USER_LIST,
- render: () => <>user list>,
- },
- {
- path: ROUTE_PAGE_MODELS,
- render: () => <>page models>,
- },
- ];
-```
-
-Next, import the routes constants inside `LinkMenu.js` and change
-accordingly the **to** property of the `` component:
-
-```js
- ...
- import {
- ROUTE_USER_LIST,
- ROUTE_PAGE_MODELS,
- } from 'app-init/routes';
-
- const LinkMenu = () => (
- <>
- }
- to={ROUTE_USER_LIST}
- />
- }
- to={ROUTE_PAGE_MODELS}
- />
- >
- );
- ...
-```
-
-Next clicks on the links in the menu will change the routes and display
-the content defined in the `App.js` file.
-
-## state
-
-The state in src/babel.js is the combined reducer of the app, the
-rootReducer.js contains the combined reducer of the app and exports it,
-but also contains the entire reducer of the app when running in
-standalone mode.
-
-```js
- export const testing = combineReducers({
- // implement here your app specific reducers
- });
-
- export default combineReducers({
- apps: combineReducers({ testing }),
- api,
- currentUser,
- form,
- loading,
- locale,
- messages,
- modal,
- pagination,
- });
-```
-
-The app specific reducers are stored inside the `apps` object, this is
-done to avoid possible name collisions with any reducer stored inside
-app-builder when running the app in integrated mode.
-
-## Customizing the Reducers
-
-Next we will be creating the two reducers for the user list and page
-models. They will be created inside two new directories
-`src/state/apps/testing/userList/` and
-`src/state/apps/testing/pageModels`. The `types.js` files will contain
-the two action types that we’ll need.
-
-`userList/types.js`
-
- // eslint-disable-next-line import/prefer-default-export
- export const ADD_USERS = 'apps/testing/add-users';
-
-`pageModels/types.js`
-
- // eslint-disable-next-line import/prefer-default-export
- export const ADD_PAGE_MODELS = 'apps/testing/page-models/add-page-models';
-
-The value of both constants contain the whole namespace
-`apps/testing/REDUCER` this is done to avoid any possible name collision
-when running the app in integrated mode.
-
-Next create both actions files:
-
-`userList/actions.js`
-
-```js
- import {
- ADD_USERS,
- } from 'state/apps/testing/userList/types';
-
- // eslint-disable-next-line import/prefer-default-export
- export const addUsers = users => ({
- type: ADD_USERS,
- payload: users,
- });
-```
-
-`pageModels/actions.js`
-
-```js
- import {
- ADD_PAGE_MODELS,
- } from 'state/apps/testing/pageModels/types';
-
- // eslint-disable-next-line import/prefer-default-export
- export const addPageModels = pageModels => ({
- type: ADD_PAGE_MODELS,
- payload: pageModels,
- });
-```
-
-then the selectors:
-
-`userList/selectors.js`
-
-```js
- import { createSelector } from 'reselect';
-
- export const getUserList = state => state.apps.testing.userList;
- export const getList = createSelector(getUserList, userList => userList.list);
-```
-
-`pageModels/selectors.js`
-
-```js
- import { createSelector } from 'reselect';
-
- export const getPageModels = state => state.apps.testing.pageModels;
- export const getList = createSelector(getPageModels, pageModels => pageModels.list);
-```
-
-And finally the reducers. The default state is going to contain some
-sample data for us to display.
-
-`userList/reducer.js`
-
-```js
- import { ADD_USERS } from 'state/apps/testing/userList/types';
-
- const defaultState = {
- list: [
- {
- username: 'admin',
- registration: '2018-01-08 00:00:00',
- lastLogin: '2018-01-08 00:00:00',
- lastPasswordChange: '2018-01-08 00:00:00',
- status: 'active',
- passwordChangeRequired: true,
- profileAttributes: {
- fullName: 'admin',
- email: 'admin@entando.com',
- },
- },
- {
- username: 'user1',
- registration: '2018-01-08 00:00:00',
- lastLogin: '2018-01-08 00:00:00',
- lastPasswordChange: '2018-01-08 00:00:00',
- status: 'disabled',
- passwordChangeRequired: true,
- profileAttributes: {
- fullName: 'User Name',
- email: 'user1@entando.com',
- },
- },
- ],
- };
-
- const reducer = (state = defaultState, action = {}) => {
- switch (action.type) {
- case ADD_USERS: {
- return { ...state, list: action.payload };
- }
-
- default: return state;
- }
- };
-
- export default reducer;
-```
-
-`pageModels/reducer.js`
-
-```js
- import { ADD_PAGE_MODELS } from 'state/apps/testing/pageModels/types';
-
- const defaultState = {
- list: [
- {
- code: 'home',
- descr: 'Home Page',
- configuration: {
- frames: [
- {
- pos: 0,
- descr: 'Navbar',
- sketch: {
- x1: 0,
- y1: 0,
- x2: 2,
- y2: 0,
- },
- },
- {
- pos: 1,
- descr: 'Navbar 2',
- sketch: {
- x1: 3,
- y1: 0,
- x2: 5,
- y2: 0,
- },
- },
- ],
- },
- template: '',
- },
- {
- code: 'service',
- descr: 'Service Page',
- configuration: {
- frames: [
- {
- pos: 0,
- descr: 'Navbar',
- sketch: {
- x1: 0,
- y1: 0,
- x2: 2,
- y2: 0,
- },
- },
- {
- pos: 1,
- descr: 'Navbar 2',
- sketch: {
- x1: 3,
- y1: 0,
- x2: 5,
- y2: 0,
- },
- },
- ],
- },
- template: '',
- },
- ],
- };
-
- const reducer = (state = defaultState, action = {}) => {
- switch (action.type) {
- case ADD_PAGE_MODELS: {
- return { ...state, list: action.payload };
- }
-
- default: return state;
- }
- };
-
- export default reducer;
-```
-
-Last, we can add the two reducers just created to the
-`src/state/rootReducer.js`
-
-```js
- ...
- import userList from 'state/apps/testing/userList/reducer';
- import pageModels from 'state/apps/testing/pageModels/reducer';
-
- export const testing = combineReducers({
- pageModels,
- userList,
- });
- ...
-```
-
-we will now be able to see with the `reduxDevTools` in our browser. To
-view this state in your reduxDevTools go to:
-
-`State -→ apps -→ testing -→ pageModels` and
-`State -→ apps -→ testing -→ userList`
-
-# Creating the UI Components
-
-At this point, both routes created should be rendering a simple string.
-We will next create the actual component that will be rendered inside
-the page.
-
-## userList
-
-Inside `src/ui/userList/` create the `List` component. Create the
-`userList` directory and `List.js` file in that directory.
-
-```js
- import React from 'react';
-
- import {
- Grid,
- TablePfProvider,
- } from 'patternfly-react';
-
- const List = () => {
- const data = [
- {
- username: 'admin',
- registration: '2018-01-08 00:00:00',
- },
- {
- username: 'user1',
- registration: '2018-01-08 00:00:00',
- },
- ];
-
- const tr = data.map(row => (
-
- {row.username} |
- {row.registration} |
-
- ));
-
- return (
-
-
-
-
- username |
- registration |
-
-
-
- {tr}
-
-
-
- );
- };
-
- export default List;
-```
-
-Next, change the route inside `src/ui/App.js`. Add the import below and
-update the component to reference the List component created in the
-prior step.
-
-```js
- ...
- import List from 'ui/userList/List';
- ...
- {
- path: ROUTE_USER_LIST,
- component: List,
- },
- ...
-```
-
-The table will now display correctly when clicking on the menu item.
-
-### connecting to the store
-
-Next let’s connect the component to the store to get the data from the
-reducer.
-
-The first step is creating the `ListContainer.js` next to the `List`
-component file.
-
-```js
- import { connect } from 'react-redux';
- import { getList } from 'state/apps/testing/userList/selectors';
-
- import List from 'ui/userList/List';
-
- export const mapStateToProps = state => ({
- data: getList(state),
- });
-
- export default connect(
- mapStateToProps,
- null,
- )(List);
-```
-
-And then update the List component to receive the property. The List
-file should now look like this:
-
-```js
- import React from 'react';
- import PropTypes from 'prop-types';
-
- import {
- Grid,
- TablePfProvider,
- } from 'patternfly-react';
-
- const List = ({ data }) => {
- const tr = data.map(row => (
-
- {row.username} |
- {row.registration} |
-
- ));
-
- return (
-
-
-
-
- username |
- registration |
-
-
-
- {tr}
-
-
-
- );
- };
-
- export default List;
-```
-
-Make sure that you remove the predefined `data` const since the data
-will now be coming from the reducer, on top of defining PropTypes rules
-for validating and giving a default for the injected property `data`.
-
-Once complete, update the component used in the route inside `App.js`.
-Update the import to the container and update the component in
-`ROUTE_USER_LIST` to the new ListContainer.
-
-```js
- ...
- import ListContainer from 'ui/userList/ListContainer';
- ...
- {
- path: ROUTE_USER_LIST,
- component: ListContainer,
- },
- ...
-```
-
-Go back to your app. We will now see the data inside the table
-reflecting the content of the storage.
-
-## Page Models
-
-inside `src/ui/pageModels/` we are going to create the `List` component
-
-```js
- import React from 'react';
- import PropTypes from 'prop-types';
-
- import {
- Grid,
- TablePfProvider,
- } from 'patternfly-react';
-
- const List = ({ data }) => {
- const tr = data.map(row => (
-
- {row.username} |
- {row.registration} |
-
- ));
-
- return (
-
-
-
-
- username |
- registration |
-
-
-
- {tr}
-
-
-
- );
- };
-
- List.propTypes = {
- data: PropTypes.arrayOf(PropTypes.shape({})),
- };
-
- List.defaultProps = {
- data: [],
- };
-
- export default List;
-```
-
-Next change the route inside `src/ui/App.js`
-
-```js
- ...
- import ListPageModels from 'ui/pageModels/List';
- ...
- {
- path: ROUTE_PAGE_MODELS,
- component: ListPageModels,
- },
- ...
-```
-
-The table will now be displayed correctly when clicking on the menu
-item.
-
-### Connecting to the Store
-
-Next, connect the component to the store to get the data from the
-reducer.
-
-The very first thing we’ll do is create the `ListContainer.js` next to
-the `List` component file.
-
-```js
- import { connect } from 'react-redux';
- import { getList } from 'state/apps/testing/pageModels/selectors';
-
- import List from 'ui/pageModels/List';
-
- export const mapStateToProps = state => ({
- data: getList(state),
- });
-
- export default connect(
- mapStateToProps,
- null,
- )(List);
-```
-
-And then update the List component to receive the property. The whole
-List component will have this content:
-
-```js
- import React from 'react';
- import PropTypes from 'prop-types';
-
- import {
- Grid,
- TablePfProvider,
- } from 'patternfly-react';
-
- const List = ({ data }) => {
- const tr = data.map(row => (
-
- {row.code} |
- {row.descr} |
-
- ));
-
-
- return (
-
-
-
-
- code |
- descr |
-
-
-
- {tr}
-
-
-
- );
- };
-
- List.propTypes = {
- data: PropTypes.arrayOf(PropTypes.shape({})),
- };
-
- List.defaultProps = {
- data: [],
- };
- export default List;
-```
-
-Next make sure that you remove the predefined `data` const since the
-data will be coming from the reducer, on top of defining PropTypes rules
-for validating and giving a default for the injected property `data`.
-
-Once complete, update the component used in the route inside `App.js`
-
-```js
- ...
- import PageModelsListContainer from 'ui/pageModels/ListContainer';
- ...
- {
- path: ROUTE_PAGE_MODELS,
- component: PageModelsListContainer,
- },
- ...
-```
-
-You will now see the data inside the table reflecting the content of the
-storage.
-
-# Connecting the app to an Entando core instance
-
-By default the app is using mocks and not connecting to any Entando core
-instance.
-
-Because the app is making use of `@entando/apimanager` we can easily
-change this by setting up two `.env` variables inside the `.env` file in
-the project root:
-
-```
- REACT_APP_DOMAIN=http://localhost:8080/entando-app
- REACT_APP_USE_MOCKS=false
-```
-
-The `REACT_APP_DOMAIN` must pointing towards the domain and container
-where the Entando instance is running and **must not** contain trailing
-slashes.
-
-Once this is done to make the change happen we will have to stop the app
-using `ctrl + c` and re run it with `npm start`.
-
-Now the toast stating *This application is using mocks* won’t be popping
-up anymore.
-
-You can make sure that the configuration is correct by looking at the
-network section in the browser dev tools. By default the app
-automatically makes an admin login against a plain Entando instance to
-authenticate the user and to be able to consume any protected api.
-
-This is not an ideal scenario and it is meant to be used only for
-debugging purposes for many reasons:
-
-- the username and password should never be hardcoded in your app
-
-- if authentication is required the user should be the one performing
- the login action
-
-- the plain default passwords in use won’t be useful against a proper
- production instance of Entando
-
-## Adding the API Calls
-
-We are now going to add api calls for both users and page models to
-retrieve the data live instead of relying on our store’s default state.
-
-Inside `src/api` create the `users.js` file:
-
-```js
- import { makeRequest, METHODS } from '@entando/apimanager';
-
- // eslint-disable-next-line import/prefer-default-export
- export const getUsers = (page = { page: 1, pageSize: 10 }, params = '') => (
- makeRequest(
- {
- uri: `/api/users${params}`,
- method: METHODS.GET,
- mockResponse: {},
- useAuthentication: true,
- },
- page,
- )
- );
-```
-
-and then create the `pageModels.js` file:
-
-```js
- import { makeRequest, METHODS } from '@entando/apimanager';
-
- // eslint-disable-next-line import/prefer-default-export
- export const getPageModels = (page = { page: 1, pageSize: 10 }, params = '') => makeRequest({
- uri: `/api/pageModels${params}`,
- method: METHODS.GET,
- mockResponse: {},
- useAuthentication: true,
- }, page);
-```
-
-## Creating the Thunk
-
-In order to use the api call we next create a thunk action, which is a
-redux action with side effects, like an API call.
-
-inside the `src/state/apps/testing/userList/actions.js` file we are
-going to add the new action:
-
-```js
- ...
- import { addErrors } from '@entando/messages';
- import {
- getUsers,
- } from 'api/users';
- ...
-
- // thunks
-
- export const fetchUsers = (page = { page: 1, pageSize: 10 }, params = '') => dispatch => (
- new Promise((resolve) => {
- getUsers(page, params).then((response) => {
- response.json().then((json) => {
- if (response.ok) {
- dispatch(addUsers(json.payload));
- } else {
- dispatch(addErrors(json.errors.map(err => err.message)));
- }
- resolve();
- });
- }).catch(() => {});
- })
- );
-```
-
-Next do the same inside `src/state/apps/testing/pageModels/actions.js`:
-
-```js
- ...
- import { addErrors } from '@entando/messages';
- import {
- getPageModels,
- } from 'api/pageModels';
- ...
-
- // thunks
-
- export const fetchPageModels = (page = { page: 1, pageSize: 10 }, params = '') => dispatch => (
- new Promise((resolve) => {
- getPageModels(page, params).then((response) => {
- response.json().then((data) => {
- if (response.ok) {
- dispatch(addPageModels(data.payload));
- resolve();
- } else {
- dispatch(addErrors(data.errors.map(err => err.message)));
- resolve();
- }
- });
- }).catch(() => {});
- })
- );
-```
-
-Now with two exports, it is safe to remove the
-`eslint-disable-next-line` comment on line 5 of both files.
-
-## changing the mapDispatchToProps in the containers
-
-Next, in order to pass the newly created thunk to both List components,
-we’ll update the containers accordingly, as:
-
-`src/ui/userList/ListContainer.js`
-
-```js
- ...
- import { fetchUsers } from 'state/apps/testing/userList/actions';
- ...
- export const mapDispatchToProps = dispatch => ({
- fetch: () => dispatch(fetchUsers()),
- });
-
- export default connect(
- mapStateToProps,
- mapDispatchToProps,
- )(List);
-```
-
-`src/ui/pageModels/ListContainer.js`
-
-```js
- ...
- import { fetchPageModels } from 'state/apps/testing/pageModels/actions';
- ...
- export const mapDispatchToProps = dispatch => ({
- fetch: () => dispatch(fetchPageModels()),
- });
-
- export default connect(
- mapStateToProps,
- mapDispatchToProps,
- )(List);
-```
-
-## Updating the List components
-
-Both List components were simple components with only a `render` method,
-therefore could be declared as simple constants.
-
-Next we will fetch data during the `componentDidMount` life cycle event
-which will require we turn the constant into a class on top of changing
-the PropTypes to add the new fetch method passed down to the component.
-
-`src/ui/userList/List.js`
-
-```js
- import React, { Component } from 'react';
- ...
- class List extends Component {
- componentDidMount() {
- const { fetch } = this.props;
- fetch();
- }
-
- render() {
- const { data } = this.props;
- const tr = data.map(row => (
-
- {row.username} |
- {row.registration} |
-
- ));
-
- return (
-
-
-
-
- username |
- registration |
-
-
-
- {tr}
-
-
-
- );
- }
- }
-
- List.propTypes = {
- data: PropTypes.arrayOf(PropTypes.shape({})),
- fetch: PropTypes.func,
- };
-
- List.defaultProps = {
- data: [],
- fetch: () => {},
- };
-```
-
-`src/ui/pageModels/List.js`
-
-```js
- import React, { Component } from 'react';
- ...
- class List extends Component {
- componentDidMount() {
- const { fetch } = this.props;
- fetch();
- }
-
- render() {
- const { data } = this.props;
- const tr = data.map(row => (
-
- {row.code} |
- {row.descr} |
-
- ));
-
- return (
-
-
-
-
- code |
- descr |
-
-
-
- {tr}
-
-
-
- );
- }
- }
-
- List.propTypes = {
- data: PropTypes.arrayOf(PropTypes.shape({})),
- fetch: PropTypes.func,
- };
-
- List.defaultProps = {
- data: [],
- fetch: () => {},
- };
-```
-
-## clear the default value of the reducer
-
-Now we should be fetching data from the server, therefore we can safely
-make the list key in the `defaultState` object an empty array:
-
-`src/state/apps/testing/userList/reducer.js`
-
-```js
- ...
- const defaultState = {
- list: [],
- };
- ...
-```
-
-`src/state/apps/testing/pageModels/reducer.js`
-
-```js
- ...
- const defaultState = {
- list: [],
- };
- ...
-```
-
-# adding additional dependencies
-
-It may be necessary to set additional dependencies for your project. If
-the need arises, it is important to remember a few rules:
-
-Only actual dependencies that are not already included in `app-builder`
-can be added as pure dependencies. Every other dependency must either be
-a `devDependency` or `peerDependency`.
-
-If you are not careful you may end up with duplicated dependencies that
-**will** result in errors manifesting themselves when running the app
-inside App Builder.
-
-# running the app in integrated mode within App Builder
-
-After running `npm install` in the App Builder, the user can run the
-`npm run app-install ` command to install the app.
-
-This command will trigger a download of the app from npm and the
-installation of its component within App Builder. After the installation
-process is complete, it will be possible to either `npm start` or
-`npm build` App Builder.
-
-To install a dev app, like the one developed in this tutorial which have
-not been previously published on npm, you will need to use additional
-flags and will have to run a few additional commands.
-
-**Before running the Install command** make sure that you have
-uninstalled all existing peer and dev dependencies to avoid collision
-with app builder. To do so, from the app builder app directory
-(`testing`, in this tutorial) just run in the correct order the
-following commands:
-
-`npm run babel`
-
-`npm i --only=production`
-
-The first will create the dist directory that will be needed by App
-Builder while the second one will uninstall anything but production
-dependencies.
-
-Next, from the App Builder directory, run the install command with these
-additional flags:
-
-- `-d` specify the relative path where the app is installed. When
- using this flag the appId should be the normalized app name, without
- the `@entando/` prefix.
-
-- `-p` specify the package name if it is different from the appId
-
-to use flags you will have to use the double dash in the command:
-
-`npm run app-install — cms -d ../testing -p @entando/testing`
-
-**the value in the `-p` flag should always match the actual name of the
-app that is going to be installed inside App Builder**. You can check
-your app name inside the `package.json` file of your app.
-
-If you experience problems after running the build command delete the
-`node_modules` directory before running the second command.
-