Building the UX web application (tutorial)
Build a complete UX Web application with ReactJS and IBM Carbon components by creating models, data sources, views, and applications in Maximo® Real Estate and Facilities, then developing the frontend using create-react-app template with data tables, services, and routing.
In this tutorial, you will be guided to build a UX Web Application with ReactJS and IBM Carbon components.
Before you begin
https://<workspace_id>.facilities.<mas_domain>Where
<workspace_id> and
<mas_domain> are the values for your
Maximo Real Estate and
Facilities environment. Node.js or npm installed on your computer, then access https://nodejs.org to download and install Node.js (npm is
installed as part of the Node.js installation). For previous releases, see https://nodejs.org/en/download/releases/.To check if you have Node.js
installed, run this command in your terminal:
node
-vTo confirm that you have npm installed, you can run this command in
your terminal:
npm -vStep 1. Add the Model
From the side navigation menu, select Tools. In the portal, select Model Designer. Click Add. Enter the name, exposed name, and ID of your model. The exposed name should be a browser-friendly string. For our example, we'll enter the following information:
- Name
- My First App Model
- Exposed Name
- myFirstApp
- ID
- My First App Model
Then click Create.

Step 2. Add the Data Source and Fields for Current User
Next, in the Data Sources section of your model, click Add. Enter the following information:
- Name
- Current User
- Exposed Name
- currentUser
- Data Source Type
- CURRENT_USER
Next, in the Fields section of your data source, click Quick Add for two fields. Enter the following information:
- Name
- (1) triFirstNameTX, (2) triLastNameTX
- Exposed Name
- (1) firstName, (2) lastName
- Field Name
- (1) triFirstNameTX, (2) triLastNameTX
- Data Type
- (1) STRING, (2) STRING
Then click Create. Finally, Save & Close your model.

Step 3. Add the View
From the side navigation menu, select Tools. In the portal, select Web View Designer. Click Add. Enter the name, exposed name, and ID of your view. For our example, we'll enter the following information:
- Name
- My First App
- Exposed Name
- my-first-app
- ID
- My First App
- View Type
- WEB_APP
- Root Folder
- Messages Folder
- Index filename
Click Create. Then Save & Close.

Step 4. Add the Model-and-View
From the side navigation menu, select Tools. In the portal, select Model and View Designer. Click Add. Enter the name, exposed name, and ID of your model-and-view. For our example, we'll enter the following information:
- Name
- My First App Model and View
- Exposed Name
- myFirstApp
- ID
- My First App Model and View
- Model Name
- Select
- View Name
- Select
- View Type
- Select
Click Create. Then Save & Close.

Step 5. Add the Application
From the side navigation menu, select Tools. In the portal, select Application Designer. Click Add. Enter the name, exposed name, and ID of your application. For our example, we'll enter the following information:
- Name
- My First App
- Exposed Name
- myFirstApp
- ID
- My First App
- Label
- My first app
- App Type
- Select
- App Name
- Select
- Instance ID
- -1
Click Create. Then Save & Close.

Step 6. Create the Skeleton Application from a Template
A
Maximo Real Estate and
Facilities template can be used
with the NPM-based create-react-app tool to build a skeleton UX Web
Application. This is the best way to start building a UX Web Application with ReactJS and
IBM Carbon components.
To create a new UX Web Application from this template, run this command in your terminal:
npx create-react-app my-first-app --template @tririga/cra-template --use-npm
Step 7. Run the Application Locally
Now let's run the UX Web Application that you created. In the my-first-app folder that was created, make a copy of the .env.development.local.template file and rename the copied file to .env.development.local. Open the .env.development.local file and set the values for the following variables:
REACT_APP_INSTANCE_ID: Instance ID from the application metadataREACT_APP_TRIRIGA_URL: URL of the Maximo Real Estate and Facilities serverREACT_APP_CONTEXT_PATH: Maximo Real Estate and Facilities context path . (No longer used)REACT_APP_MODEL_AND_VIEW: Exposed name of the model-and-viewREACT_APP_BASE_PATH: Path when running the app on the local development serverREACT_APP_EXPOSED_NAME: Exposed name of the applicationREACT_APP_SSO: If SSO is enabled on the server, then true; otherwise, false
For our example, we'll enter the following information, where
REACT_APP_TRIRIGA_URL and REACT_APP_CONTEXT_PATH are the specific
values for your
Maximo Real Estate and
Facilities
environment:
REACT_APP_INSTANCE_ID=-1
REACT_APP_TRIRIGA_URL=https://www.tririga-dev.com/dev
REACT_APP_CONTEXT_PATH=/dev
REACT_APP_MODEL_AND_VIEW=myFirstApp
REACT_APP_BASE_PATH=/
REACT_APP_EXPOSED_NAME=myFirstApp
REACT_APP_SSO=false
After you've entered the information, change directory (cd) and run this command
in your terminal:
cd my-first-app
npm start
This command automatically opens your app home page in a new tab of your default browser. By default, the URL of an app that runs locally is: https://localhost:3000. To check if your app displays some information about your user, click the Current User button.
Congratulations! You've built your first Maximo Real Estate and Facilities UX Web Application with ReactJS components. Create a new page to display all of the buildings.

Step 8. Add the Data Source and Fields for All Buildings
First, let's add a data source to query all of the buildings in Maximo Real Estate and Facilities.
From the side navigation menu, select Tools. In the portal, select Model Designer. Select the My First App Model.
Next, in the Data Sources section of your model, click Add. Enter the following information:
- Name
- All Buildings
- Exposed Name
- allBuildings
- Data Source Type
- QUERY
- Multiple Records
- Yes
- Module
- Location
- Business Object
- Building (triBuilding)
- Query Name
- triBuilding - Building Details
Next, in the Fields section of your data source, click Quick Add for two fields. Enter the following information:
- Name
- (1) Building, (2) Parent
- Exposed Name
- (1) building, (2) parentProperty
- Field Name
- (1) Building, (2) Parent
- Data Type
- (1) STRING, (2) STRING
Then click Create. Finally, Save & Close your model.

Step 9. Add the Method to Interact with the Data Source
Open the my-first-app folder by using the integrated development environment (IDE) of your choice. For our example, the following screenshots are taken from Microsoft Visual Studio Code. The code that interacts with the data sources are placed under: /src/model/datasources. Under that folder, create a new file that is named BuildingsDS.js.

Open the BuildingsDS.js file and add the following code:
import { getAppModel } from "../AppModel";
import { DatasourceNames } from "../../utils";
export async function getAllBuildings() {
const response = await getAppModel().getRecord(
DatasourceNames.BUILDINGS_DS_NAME
);
return response.data;
}
Basically, this code gets the model object and then calls the getRecord method
to get the data from the BUILDINGS_DS_NAME data source.
Next, let's create the BUILDINGS_DS_NAME constant and set its value to
allBuildings, the exposed name of the All Buildings data source. Under the
/src/utils/constants folder, open the DatasourceNames.js
file and add the new const (constant) as follows:
export const CURRENT_USER_DS_NAME = "currentUser";
export const BUILDINGS_DS_NAME = "allBuildings";
Export the BuildingsDS from the model index.js file. Under
the /src/model folder, open the index.js file and add the
export of the BuildingsDS as follows:
import { createAppModel, getAppModel } from "./AppModel";
import * as CurrentUserDS from "./datasources/CurrentUserDS";
import * as BuildingsDS from "./datasources/BuildingsDS";
export { createAppModel, getAppModel, CurrentUserDS, BuildingsDS };
Step 10. Add the Service to Get All Buildings
A service encapsulates the logic to run the application actions. These actions are usually triggered by a user or event. The services are placed under: /src/services. Under that folder, create a new file that is named BuildingsServices.js.

Open the BuildingsServices.js file and add the following code:
import { LoadingServices } from ".";
import { BuildingsDS } from "../model";
export async function getAllBuildings() {
let buildings = [];
try {
LoadingServices.setLoading("getAllBuildings", true);
buildings = await BuildingsDS.getAllBuildings();
} finally {
LoadingServices.setLoading("getAllBuildings", false);
}
return buildings;
}
This code is a simple action that toggles the loading while calling the
BuildingsDS to get all buildings.
Export the BuildingsServices from the services
index.js file. Under the /src/services folder, open the
index.js file and add the export of the BuildingsServices as
follows:
export * as LoadingServices from "./LoadingServices";
export * as CurrentUserServices from "./CurrentUserServices";
export * as MessageServices from "./MessageServices";
export * as BuildingsServices from "./BuildingsServices";
Step 11. Add the Page to Display All Buildings
Next, let's create a new page where we will use an IBM Carbon component that is named
DataTable to display all buildings. For more information about the
DataTable component, including an example, see:
https://react.carbondesignsystem.com/?path=/docs/components-datatable-sorting--default
The pages are placed under: /src/pages. Under that folder, create a new folder that is named AllBuildingsPage. Under this new AllBuildingsPage folder, create two new files as follows:
- _AllBuildingsPage.scss: Partial Sass file that contains the styles that are used by the page
- AllBuildingsPage.js: JavaScript file that contains the component that renders the page

Open the _AllBuildingsPage.scss file and add the following code:
@use "@carbon/react/scss/config" as *;
@use "../../styles/page" as *;
.allBuildingsPage {
@include page;
&__content {
display: flex;
flex-direction: column;
}
& .#{$prefix}--data-table-container {
height: 100%;
display: flex;
flex-direction: column;
}
}
Open the AllBuildingsPage.js file and add the following code:
import React from "react";
import {
DataTable,
TableContainer,
Table,
TableHead,
TableRow,
TableHeader,
TableBody,
TableCell,
} from "carbon-components-react";
import { Routes, AppMsg } from "../../utils";
import { FooterButtons } from "../../components";
import { BuildingsServices } from "../../services";
const cssBase = "allBuildingsPage";
export default class AllBuildingsPage extends React.PureComponent {
state = {
buildings: [],
};
async loadBuildings() {
const buildings = await BuildingsServices.getAllBuildings();
this.setState({ buildings });
}
componentDidMount() {
this.loadBuildings();
}
render() {
const { buildings } = this.state;
buildings.forEach((item) => {
item.id = item._id;
});
const headers = [
{
key: "building",
header: AppMsg.getMessage(AppMsg.MESSAGES.NAME),
},
{
key: "parentProperty",
header: AppMsg.getMessage(AppMsg.MESSAGES.PARENT_PROPERTY),
},
];
return (
<div className={cssBase}>
<div className={`${cssBase}__content`}>
<DataTable rows={buildings} headers={headers}>
{({
rows,
headers,
getHeaderProps,
getRowProps,
getTableProps,
getTableContainerProps,
}) => (
<TableContainer
title={AppMsg.getMessage(AppMsg.MESSAGES.BUILDINGS)}
description={AppMsg.getMessage(
AppMsg.MESSAGES.ALL_BUILDINGS_DESCRIPTION
)}
{...getTableContainerProps()}
>
<Table {...getTableProps()} isSortable>
<TableHead>
<TableRow>
{headers.map((header) => (
<TableHeader
key={header.key}
{...getHeaderProps({ header })}
isSortable
>
{header.header}
</TableHeader>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.id} {...getRowProps({ row })}>
{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)}
</DataTable>
</div>
<FooterButtons
secondaryLabel={AppMsg.getMessage(AppMsg.BUTTONS.HOME)}
secondaryRoute={Paths.HOME}
/>
</div>
);
}
}
Basically, this code loads all buildings by calling the
BuildingsServices.getAllBuildings method when the component is mounted, and then
saves the list of buildings to the component state. The render method uses the IBM
Carbon DataTable component to render a table with all buildings. Meanwhile, all of
the labels that are displayed by the page are retrieved by using the
AppMsg.getMessage method.
Import the _AllBuildingsPage.scss file into the _Pages.scss file. Under the /src/pages folder, open the _Pages.scss file and add the import of the _AllBuildingsPage.scss file as follows:
@forward "./HomePage/HomePage";
@forward "./CurrentUserPage/CurrentUserPage";
@forward "./UnauthorizedPage/AuthorizedPage";
@forward "./AllBuildingsPage/AllBuildingsPage"; // add this line
Next, let's export the AllBuildingsPage from the pages
index.js file. Under the /src/pages folder, open the
index.js file and add the export of the AllBuildingsPage as
follows:
import HomePage from "./HomePage/HomePage";
import CurrentUserPage from "./CurrentUserPage/CurrentUserPage";
import UnauthorizedPage from "./UnauthorizedPage/UnauthorizedPage";
import AllBuildingsPage from "./AllBuildingsPage/AllBuildingsPage";
export { HomePage, CurrentUserPage, UnauthorizedPage, AllBuildingsPage };
When you use an IBM Carbon component, you must also import the styles that are used by the component. Under the /src folder, open the index.scss file and add the import of the data-table.scss file as follows:
//Carbon components styles
@use "@carbon/react/scss/components/data-table";
@use '@carbon/react/scss/components/data-table/sort';
@use "@carbon/react/scss/components/button";
@use "@carbon/react/scss/components/loading";
@use "@carbon/react/scss/components/list";
@use "@carbon/react/scss/components/modal";
@use "@carbon/react/scss/components/notification";
Step 12. Add the Labels for the Page
All of the labels that are used by the application are defined in the JSON files that are inside the Messages Folder. Under the /src/utils/messages folder, open the messages.json file and add the following labels:
BUILDINGS: BuildingsALL_BUILDINGS_DESCRIPTION: A list of all buildings in Maximo Real Estate and FacilitiesNAME: NamePARENT_PROPERTY: Parent Property
{
"HOME_HEADER": "Welcome to the UX Web Application Home Page",
"CURRENT_HEADER": "Current user details",
"UNAUTHORIZED_TITLE": "You do not have permission to access this page.",
"UNAUTHORIZED_DESCRIPTION": "Due to either a session timeout or unauthorized access,
you do not have permission to access this page.",
"BUILDINGS": "Buildings",
"ALL_BUILDINGS_DESCRIPTION": "A list of all buildings in TRIRIGA",
"NAME": "Name",
"PARENT_PROPERTY": "Parent Property"
}Next, let's create the label constants. Under the /src/utils/messages folder, open the ApplicationMessages.js file and add the following label constants:
BUILDINGSALL_BUILDINGS_DESCRIPTIONNAMEPARENT_PROPERTY
export const MESSAGES = {
HOME_HEADER: "HOME_HEADER",
CURRENT_HEADER: "CURRENT_HEADER",
UNAUTHORIZED_TITLE: "UNAUTHORIZED_TITLE",
UNAUTHORIZED_DESCRIPTION: "UNAUTHORIZED_DESCRIPTION",
BUILDINGS: "BUILDINGS",
ALL_BUILDINGS_DESCRIPTION: "ALL_BUILDINGS_DESCRIPTION",
NAME: "NAME",
PARENT_PROPERTY: "PARENT_PROPERTY",
};Step 13. Add the Route to the Page
Add a route to the new page that we created. Under the /src/utils/constants
folder, open the Paths.js file and add the path to the
BUILDINGS route as follows:
export const HOME = "/";
export const CURRENT_USER = "/user";
export const BUILDINGS = "/buildings";
Next, add the AllBuildingsPage to the main application component. Under the
/src/app folder, open the TririgaUXWebApp.js file, add the
import of the AllBuildingsPage, and declare the AllBuildingsPage
component inside a Route element as follows:
import { HomePage, CurrentUserPage, AllBuildingsPage } from "../pages"; // update this line
…
render() {
const { loading, message } = this.state;
return (
<div className={cssBase}>
<Routes>
<Route path={Paths.CURRENT_USER} element={<CurrentUserPage />} />
<Route path={Paths.HOME} element={<HomePage />} />
<Route path={Paths.BUILDINGS} element={<AllBuildingsPage />} /> // add this line
</Routes>
<ShowAppMessages message={message} clearMessage={this.clearMessage} />
{createPortal(<Loading active={loading} withOverlay />, document.body)}
</div>
);
}
Next, we must add a new Buildings button on the home page that allows the
user to navigate to the AllBuildingsPage. Under the
/src/pages/HomePage folder, open the HomePage.js file and
configure the primary button of the FooterButtons component as follows:
export default class HomePage extends React.PureComponent {
render() {
return (
<div className={cssBase}>
<div className={`${cssBase}__header`}>
{AppMsg.getMessage(AppMsg.MESSAGES.HOME_HEADER)}
</div>
<div className={`${cssBase}__content`} />
<FooterButtons
secondaryLabel={AppMsg.getMessage(AppMsg.BUTTONS.CURRENT_USER)}
secondaryRoute={Paths.CURRENT_USER}
primaryLabel={AppMsg.getMessage(AppMsg.MESSAGES.BUILDINGS)} // add this line
primaryRoute={Paths.BUILDINGS} // add this line
/>
</div>
);
}
}
Finally, return to your browser to check the new page that you created.
- If you closed the browser tab with your page, open a new tab with your local URL: http://localhost:3000.
- If your application is not running, verify that your local server is running (Step 7).
- If necessary, check your browser console for errors.
Congratulations! You've built your first Maximo Real Estate and Facilities UX Web Application with ReactJS and IBM Carbon components.
