Inventory UI
Develop and deploy the UI component of the inventory application
Setup
Get the initial project created and register the pipeline for automated builds. Detailed instructions for each of these steps can be found in the Deploying an App guide.
Create a new repository from the React UI Patterns Code Pattern into your Git org - https://github.com/IBM/template-node-react/generate
In order to prevent naming collisions, name the repository
inventory-management-ui-{your initials}
replacing{your initials}
with your actual initials.Clone the new repository to your machine
Run
npm install
to install the project dependenciesGo into the repository directory cloned and execute the following
oc sync dev-{your initials} --devLog into the cluster from the command-line then register the pipeline
oc pipeline --tektonreplacing
{your initials}
with your actual initialsOpen the pipeline to see it running
Create the initial components
The React Code Pattern comes with a set UI components that implement 12 common UI Design Patterns. In the initial UI, all of the components are included to create an interactive example of how they work. The first step of building an application with the React Code Pattern is to remove those components from the menu and to create new components built from the pattern components.
Based on the requirements of this first use case, we will create a StockItemList component based on the TableList pattern.
- Open a terminal and start the application in development mode to see the initial UI and the changes as we make them
npm run start:dev
Access the running service. This service runs on port 3000.
Make a copy of the
TableList
pattern component from thepattern-component
directory into thecomponents
folder. Rename the file and the class inside toStockItemList
.
client/src/components/StockItemList.jsximport React, { Component } from "react";import {StructuredListWrapper,StructuredListRow,StructuredListCell,StructuredListHead,StructuredListBody,StructuredListInput,Icon
Update UIShell.jsx
- Update the
header
variable to whatever name you want. “Big Blue Widgets” is used in the example - Update the
menuTitle
to “Inventory Management” - Remove all the values from
menuItems
- Update the
client/src/components/UIShell.jsxclass UIShell extends Component {header = "Big Blue Widgets";menuTitle = "Inventory Management";menuItems = ["Stock Items",];...}
Update UIShellBody.jsx
- Remove all of the pattern values from the
components
map and add one entry for Stock Item List. The value on the left is the label that is displayed and the value on the right is the class that should be loaded (e.g."Stock Items": StockItemList
). Note: The label value needs to match the one used onUIShell
- Update the Use
Stock Items
as the default pattern name when none is given
- Remove all of the pattern values from the
client/src/components/UIShellBody.jsximport React, {Component} from "react";import "../pattern-components/patterns.scss";import StockItemList from "./StockItemList";class UIShellBody extends Component {components = {"Stock Items": StockItemList};
- With the application running in the first terminal, open a second terminal in the repository directory and push the changes we’ve made to the repository
git add .git commit -m "Initial shell components"git push
Return to the pipeline to see it running
Refresh the browser from earlier (or follow the steps from before to use
oc endpoints
to open the browser). The changes we just made should be reflected in the UI.
Update StockItemList contents
Now that we’ve created the initial components, we can start to customize the StockItemList to match the data for our application.
Start the application in development mode (if not already running) with
npm run start:dev
Update the
title
andsubtitle
with values for our Stock Items view.Update the
columns
anddata
fields with the list of columns and sample data to match the UI. Set theformatters
to{}
for now.The value in the
columns
array maps to one of the attributes in our data values (e.g.name
refers to the name attribute)The result of these changes should look like the following:
client/src/components/StockItemList.jsxclass StockItemList extends Component {title = 'Stock Items';subtitle = 'This is the current inventory of items';columns = ["name","description","stock","unitPrice",
View the new data in your local UI:
http://localhost:3000/
Push the changes we’ve made to the repository
git add .git commit -m "Updates the StockItemsList view"git push
- Look at the Jenkins pipeline and the deployed app
Add a service component to get mock Stock Items
So far, we’ve built a UI that displays a hard-coded set of data in a table. Eventually, we want to display dynamic data provided from a database in the table. As a first step towards that goal, we need to separate the UI logic from the logic that retrieves the data. We will do that with a service component. For this first pass the service component will just return mock data.
Create a directory called
services
under the client/src folderCreate a file named
stock-item-mock.service.js
in the service directory. Our StockItem service component will have a single asynchronous function calledlistStockItems()
that returns a list of StockItems.
client/src/services/stock-item-mock.service.jsexport class StockItemMockService {async listStockItems() {return [];}}
- Implement the service by copying the data array from
StockItemList
and returning it in the function. You can add a call totimer()
to simulate wait time
client/src/services/stock-item-mock.service.jsimport timer from '../util/timer';export class StockItemMockService {async listStockItems() {// wait 1 second before returning dataawait timer(1000);return [{
- Update the components to pass the service in the properties
client/src/App.test.jsximport React from 'react';import ReactDOM from 'react-dom';import App from './App';import {StockItemMockService} from "./services/stock-item-mock.service";describe('App', () => {test('canary verifies test infrastructure', () => {expect(true).toEqual(true);});
client/src/App.jsximport React, { Component } from "react";import UIShell from "./components/UIShell";import "./App.scss";import {StockItemMockService} from "./services/stock-item-mock.service";class App extends Component {constructor(props) {super(props);
client/src/components/UIShell.jsx...class UIShell extends Component {...render() {return (<div><Header aria-label="IBM Platform Name">
client/src/components/UIShellBody.jsx...class UIShellBody extends Component {components = {"Stock Items": StockItemList};defaultComponent = "Stock Items";render() {
- Update
StockItemList
to use the provided service
src/components/StockItemList.jsx...class StockItemList extends Component {...constructor(props) {super(props);this.state = {data: [],
- Update the render UI function in
StockItemList
to display the values in UI
client/src/components/StockItemList.jsxrenderRow = (row, id) => {return (<StructuredListRow key={id} onClick={() => this.onRowClick(id)}><div><StructuredListInputid={`row-${id}`}value="row-0"title="row-0"name="row-0"
client/src/components/StockItemList.jsxrender() {const data = this.state.data;return (<div className="bx--grid pattern-container"><Headertitle={this.title}subtitle={this.subtitle}
View the new data in your local UI:
http://localhost:3000/
Push the changes we’ve made to the repository
git add .git commit -m "Adds a mock service"git push
- Look at the Jenkins pipeline and the deployed app
Add a service that calls the BFF
Now that we have a mock service that injects data, we can build an implementation of the service
that calls our BFF. For the service, we will use a package called superagent
to make the calls
to the BFF.
- With npm, install the
superagent
and@types/superagent
dependencies
npm i -s superagentnpm i -D @types/superagent
- Create a service implementation in the
services
directory calledstock-item.service.js
client/src/services/stock-item.service.jsexport class StockItemService {async listStockItems() {return [];}}
- Add an implementation of
listStockItems()
that calls the BFF through the/api
proxy
client/src/services/stock-item.service.jsimport * as superagent from 'superagent';export class StockItemService {constructor(baseUrl) {this.baseUrl = baseUrl || '/api';}async listStockItems() {return superagent
Note: In dev mode, the proxy is configured in client/package.json
. When running with the express
server, the proxy is configured in server/routers/api.js
. By default, the value points to localhost:3001
.
- Update
App.jsx
to use the new service instead of the mock service.
client/src/App.jsximport React, { Component } from "react";import UIShell from "./components/UIShell";import "./App.scss";import {StockItemService} from "./services/stock-item.service";class App extends Component {constructor(props) {super(props);
- Modify
connectsTo
property to the values.yaml file of the Helm chart. The value of the property should match the Kubernetes service of the microservice. (For Code Pattern projects, the service name is the same as the name of the application which is that same as the name of the repository.)
chart/base/values.yaml...connectsTo: inventory-management-bff-{your initials}...
- Add a new environment variable named
API_HOST
to the list of existing environment variables in deployment.yaml. The value of this environment variable should come from theconnectsTo
value we defined. You can add| quote
to wrap the value in quotes in case the value is not formatted correctly.
chart/base/templates/deployment.yaml...env:- name: INGRESS_HOSTvalue: ""- name: PROTOCOLSvalue: ""- name: LOG_LEVELvalue: {{ .Values.logLevel | quote }}- name: API_HOST
- Push the changes we’ve made to the repository
git add .git commit -m "Updates the StockItemsList view"git push
Summary
You have now completed the Micro App Guide demonstrating the Inventory solution.