Share via


Lägga till en anpassad tjänst i webbgränssnittet för fjärrövervakningslösningsacceleratorn

Den här artikeln visar hur du lägger till en ny tjänst i webbgränssnittet för fjärrövervakningslösningsacceleratorn. Artikeln beskriver:

  • Förbereda en lokal utvecklingsmiljö.
  • Så här lägger du till en ny tjänst i webbgränssnittet.

Exempeltjänsten i den här artikeln innehåller data för ett rutnät som artikeln Lägg till ett anpassat rutnät i webbgränssnittet för fjärrövervakningslösningsacceleratorn visar hur du lägger till.

I ett React program interagerar en tjänst vanligtvis med en serverdelstjänst. Exempel i acceleratorn Fjärrövervakningslösning är tjänster som interagerar med IoT Hub Manager och mikrotjänster för konfiguration.

Förutsättningar

För att slutföra stegen i den här instruktionsguiden behöver du följande programvara installerad på din lokala utvecklingsdator:

Innan du börjar

Du bör slutföra stegen på sidan Lägg till en anpassad sida i artikeln Om snabbaccelerator för fjärrövervakningslösning innan du fortsätter.

Lägg till en tjänst

Om du vill lägga till en tjänst i webbgränssnittet måste du lägga till källfilerna som definierar tjänsten och ändra vissa befintliga filer för att göra webbgränssnittet medvetet om den nya tjänsten.

Lägg till de nya filerna som definierar tjänsten

För att komma igång innehåller mappen src/walkthrough/services de filer som definierar en enkel tjänst:

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);
  }
}

Mer information om hur tjänster implementeras finns i Introduktionen till reaktiv programmering som du har saknat.

modell/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);

Kopiera exampleService.js till mappen src/services och kopiera exampleModels.js till mappen src/services/models .

Uppdatera index.js-filen i mappen src/services för att exportera den nya tjänsten:

export * from './exampleService';

Uppdatera index.js-filen i mappen src/services/models för att exportera den nya modellen:

export * from './exampleModels';

Konfigurera anropen till tjänsten från butiken

För att komma igång innehåller mappen src/walkthrough/store/reducers en exempelreduktor:

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

Kopiera exampleReducer.js till mappen src/store/reducers .

Mer information om reducer och epos finns i redux-observable.

Konfigurera mellanprogrammet

Om du vill konfigurera mellanprogrammet lägger du till reducern i rootReducer.js-filen i mappen src/store :

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

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

Lägg till epos i filenrootEpics.js i mappen 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()
];

Nästa steg

I den här artikeln har du lärt dig om de resurser som är tillgängliga för att hjälpa dig att lägga till eller anpassa tjänster i webbgränssnittet i lösningsacceleratorn fjärrövervakning.

Nu när du har definierat en tjänst är nästa steg att lägga till ett anpassat rutnät i webbgränssnittet för fjärrövervakningslösningsacceleratorn som visar data som returneras av tjänsten.

Mer konceptuell information om acceleratorn fjärrövervakningslösning finns i Arkitektur för fjärrövervakning.