Compartir a través de


Adición de un servicio personalizado a la interfaz de usuario web del acelerador de soluciones de supervisión remota

En este artículo se muestra cómo agregar un nuevo servicio a la interfaz de usuario web del acelerador de soluciones de supervisión remota. El artículo describe:

  • Cómo preparar un entorno de desarrollo local.
  • Cómo agregar un nuevo servicio a la interfaz de usuario web.

El servicio de ejemplo de este artículo proporciona datos para una cuadrícula que el artículo de procedimientos Add a custom grid to the Remote Monitoring solution accelerator web UI (Agregar una cuadrícula personalizada a la interfaz de usuario web del acelerador de soluciones de supervisión remota) muestra cómo agregar.

En una aplicación React, un servicio normalmente interactúa con un servicio back-end. Algunos ejemplos del acelerador de soluciones de supervisión remota incluyen servicios que interactúan con el Administrador de IoT Hub y los microservicios de configuración.

Requisitos previos

Para completar los pasos de esta guía, necesita que el software siguiente esté instalado en la máquina de desarrollo local:

Antes de comenzar

Debe completar los pasos descritos en el artículo de procedimientos Adición de una página personalizada a la interfaz de usuario web del acelerador de soluciones de supervisión remota antes de continuar.

Agregar un servicio

Para agregar un servicio a la interfaz de usuario web, deberá agregar los archivos de origen que definen el servicio y modificar algunos archivos existentes para hacer que la interfaz de usuario web sea consciente del nuevo servicio.

Adición de nuevos archivos que definen el servicio

Para comenzar, la carpeta src/walkthrough/services contiene los archivos que definen un servicio sencillo:

exampleService.js


import { Observable } from 'rxjs';
import { toExampleItemModel, toExampleItemsModel } from './models';

/** Normally, you'll need to define the endpoint URL.
 * See app.config.js to add a new service URL.
 *
 * For this example, we'll just hardcode sample data to be returned instead
 * of making an actual service call. See the other service files for examples.
 */
//const ENDPOINT = Config.serviceUrls.example;

/** Contains methods for calling the example service */
export class ExampleService {

  /** Returns an example item */
  static getExampleItem(id) {
    return Observable.of(
      { ID: id, Description: "This is an example item." },
    )
      .map(toExampleItemModel);
  }

  /** Returns a list of example items */
  static getExampleItems() {
    return Observable.of(
      {
        items: [
          { ID: "123", Description: "This is item 123." },
          { ID: "188", Description: "This is item ONE-DOUBLE-EIGHT." },
          { ID: "210", Description: "This is item TWO-TEN." },
          { ID: "277", Description: "This is item 277." },
          { ID: "413", Description: "This is item FOUR-THIRTEEN." },
          { ID: "789", Description: "This is item 789." },
        ]
      }
    ).map(toExampleItemsModel);
  }

  /** Mimics a server call by adding a delay */
  static updateExampleItems() {
    return this.getExampleItems().delay(2000);
  }
}

Para obtener más información acerca de cómo se implementan los servicios, vea The introduction to Reactive Programming you've been missing (La introducción a la programación reactiva que se ha perdido).

model/exampleModels.js

import { camelCaseReshape, getItems } from 'utilities';

/**
 * Reshape the server side model to match what the UI wants.
 *
 * Left side is the name on the client side.
 * Right side is the name as it comes from the server (dot notation is supported).
 */
export const toExampleItemModel = (data = {}) => camelCaseReshape(data, {
  'id': 'id',
  'description': 'descr'
});

export const toExampleItemsModel = (response = {}) => getItems(response)
  .map(toExampleItemModel);

Copie exampleService.js a la carpeta src/services y copie exampleModels.js a la carpeta src/services/models.

Actualice el archivo index.js de la carpeta src/services para exportar el nuevo servicio:

export * from './exampleService';

Actualice el archivo index.js de la carpeta src/services/models para exportar el nuevo modelo:

export * from './exampleModels';

Configuración de las llamadas al servicio desde el almacén

Para comenzar, la carpeta src/walkthrough/store/reducers contiene un reductor de ejemplo:

exampleReducer.js

import 'rxjs';
import { Observable } from 'rxjs';
import moment from 'moment';
import { schema, normalize } from 'normalizr';
import update from 'immutability-helper';
import { createSelector } from 'reselect';
import { ExampleService } from 'walkthrough/services';
import {
  createReducerScenario,
  createEpicScenario,
  errorPendingInitialState,
  pendingReducer,
  errorReducer,
  setPending,
  toActionCreator,
  getPending,
  getError
} from 'store/utilities';

// ========================= Epics - START
const handleError = fromAction => error =>
  Observable.of(redux.actions.registerError(fromAction.type, { error, fromAction }));

export const epics = createEpicScenario({
  /** Loads the example items */
  fetchExamples: {
    type: 'EXAMPLES_FETCH',
    epic: fromAction =>
      ExampleService.getExampleItems()
        .map(toActionCreator(redux.actions.updateExamples, fromAction))
        .catch(handleError(fromAction))
  }
});
// ========================= Epics - END

// ========================= Schemas - START
const itemSchema = new schema.Entity('examples');
const itemListSchema = new schema.Array(itemSchema);
// ========================= Schemas - END

// ========================= Reducers - START
const initialState = { ...errorPendingInitialState, entities: {}, items: [], lastUpdated: '' };

const updateExamplesReducer = (state, { payload, fromAction }) => {
  const { entities: { examples }, result } = normalize(payload, itemListSchema);
  return update(state, {
    entities: { $set: examples },
    items: { $set: result },
    lastUpdated: { $set: moment() },
    ...setPending(fromAction.type, false)
  });
};

/* Action types that cause a pending flag */
const fetchableTypes = [
  epics.actionTypes.fetchExamples
];

export const redux = createReducerScenario({
  updateExamples: { type: 'EXAMPLES_UPDATE', reducer: updateExamplesReducer },
  registerError: { type: 'EXAMPLE_REDUCER_ERROR', reducer: errorReducer },
  isFetching: { multiType: fetchableTypes, reducer: pendingReducer }
});

export const reducer = { examples: redux.getReducer(initialState) };
// ========================= Reducers - END

// ========================= Selectors - START
export const getExamplesReducer = state => state.examples;
export const getEntities = state => getExamplesReducer(state).entities || {};
export const getItems = state => getExamplesReducer(state).items || [];
export const getExamplesLastUpdated = state => getExamplesReducer(state).lastUpdated;
export const getExamplesError = state =>
  getError(getExamplesReducer(state), epics.actionTypes.fetchExamples);
export const getExamplesPendingStatus = state =>
  getPending(getExamplesReducer(state), epics.actionTypes.fetchExamples);
export const getExamples = createSelector(
  getEntities, getItems,
  (entities, items) => items.map(id => entities[id])
);
// ========================= Selectors - END

Copie exampleReducer.js a la carpeta src/store/reducers.

Para obtener más información acerca del reductor y Epopeyas, consulte redux-observable.

Configurar el middleware

Para configurar el middleware, agregue el reductor al archivo rootReducer.js en la carpeta src/store:

import { reducer as exampleReducer } from './reducers/exampleReducer';

const rootReducer = combineReducers({
  ...appReducer,
  ...devicesReducer,
  ...rulesReducer,
  ...simulationReducer,
  ...exampleReducer
});

Agregue las epopeyas al archivo rootEpics.js de la carpeta src/store:

import { epics as exampleEpics } from './reducers/exampleReducer';

// Extract the epic function from each property object
const epics = [
  ...appEpics.getEpics(),
  ...devicesEpics.getEpics(),
  ...rulesEpics.getEpics(),
  ...simulationEpics.getEpics(),
  ...exampleEpics.getEpics()
];

Pasos siguientes

En este artículo, aprendió sobre los recursos que tiene a su disposición para ayudarlo a agregar o personalizar servicios en la interfaz de usuario web en el acelerador de la solución de supervisión remota.

Ya ha definido un servicio, el paso siguiente consiste en agregar una cuadrícula personalizada a la interfaz de usuario web del acelerador de soluciones de supervisión remota que muestra los datos que devuelve el servicio.

Para obtener más información conceptual sobre el acelerador de soluciones de supervisión remota, consulte Arquitectura de supervisión remota.