次の方法で共有


リモート監視ソリューション アクセラレータの Web UI にカスタム ポップアップを追加する

この記事では、リモート監視ソリューション アクセラレータの Web UI のページに新しいポップアップを追加する方法を示します。 この記事では、次の内容について説明します。

  • ローカルの開発環境を準備する方法。
  • Web UI のページに新しいポップアップを追加する方法。

この記事で使用するポップアップの例では、「Add a custom grid to the Remote Monitoring solution accelerator web UI」(リモート監視ソリューション アクセラレータの Web UI にカスタム グリッドを追加する) ハウツー記事で追加方法が示されているグリッドがページに表示されます。

前提条件

このハウツー ガイドの手順を最後まで行うには、ローカル開発マシンに次のソフトウェアがインストールされている必要があります。

開始する前に

続ける前に、次の記事の手順を完了しておく必要があります。

ポップアップの追加

Web UI にポップアップを追加するには、ポップアップが定義されているソース ファイルを追加し、既存のファイルをいくつか変更して、Web UI で新しいコンポーネントが認識されるようにする必要があります。

ポップアップが定義されている新しいファイルを追加する

作業を始められるよう、src/walkthrough/components/pages/pageWithFlyout/flyouts/exampleFlyout フォルダーにポップアップを定義したファイルが格納されています。

exampleFlyout.container.js

import { withNamespaces } from 'react-i18next';

import { ExampleFlyout } from './exampleFlyout';

export const ExampleFlyoutContainer = withNamespaces()(ExampleFlyout);

exampleFlyout.js

import React, { Component } from 'react';

import { ExampleService } from 'walkthrough/services';
import { svgs } from 'utilities';
import {
  AjaxError,
  Btn,
  BtnToolbar,
  Flyout,
  Indicator,
  SectionDesc,
  SectionHeader,
  SummaryBody,
  SummaryCount,
  SummarySection,
  Svg
} from 'components/shared';

import './exampleFlyout.scss';

export class ExampleFlyout extends Component {
  constructor(props) {
    super(props);
    this.state = {
      itemCount: 3, //just a fake count; this would often be a list of items that are being acted on
      isPending: false,
      error: undefined,
      successCount: 0,
      changesApplied: false
    };
  }

  componentWillUnmount() {
    if (this.subscription) this.subscription.unsubscribe();
  }

  apply = (event) => {
    event.preventDefault();
    this.setState({ isPending: true, successCount: 0, error: null });

    this.subscription = ExampleService.updateExampleItems()
      .subscribe(
        _ => {
          this.setState({ successCount: this.state.successCount + this.state.itemCount });
          // Update any global state in the redux store by calling any
          // dispatch methods that were mapped in this flyout's container.
        },
        error => this.setState({ error, isPending: false, changesApplied: true }),
        () => this.setState({ isPending: false, changesApplied: true, confirmStatus: false })
      );
  }

  getSummaryMessage() {
    const { t } = this.props;
    const { isPending, changesApplied } = this.state;

    if (isPending) {
      return t('walkthrough.pageWithFlyout.flyouts.example.pending');
    } else if (changesApplied) {
      return t('walkthrough.pageWithFlyout.flyouts.example.applySuccess');
    } else {
      return t('walkthrough.pageWithFlyout.flyouts.example.affected');
    }
  }

  render() {
    const { t, onClose } = this.props;
    const {
      itemCount,
      isPending,
      error,
      successCount,
      changesApplied
    } = this.state;

    const summaryCount = changesApplied ? successCount : itemCount;
    const completedSuccessfully = changesApplied && !error;
    const summaryMessage = this.getSummaryMessage();

    return (
      <Flyout header={t('walkthrough.pageWithFlyout.flyouts.example.header')} t={t} onClose={onClose}>
          {
            /**
             * Really, anything you need could go inside a flyout.
             * The following is a simple empty form with buttons to do an action or close the flyout.
             * */
          }
          <form className="example-flyout-container" onSubmit={this.apply}>
            <div className="example-flyout-header">{t('walkthrough.pageWithFlyout.flyouts.example.header')}</div>
            <div className="example-flyout-descr">{t('walkthrough.pageWithFlyout.flyouts.example.description')}</div>

            <div className="form-placeholder">{t('walkthrough.pageWithFlyout.flyouts.example.insertFormHere')}</div>

            {/** Sumarizes the action being taken; including count of items affected & status/pending indicator */}
            <SummarySection>
              <SectionHeader>{t('walkthrough.pageWithFlyout.flyouts.example.summaryHeader')}</SectionHeader>
              <SummaryBody>
                <SummaryCount>{summaryCount}</SummaryCount>
                <SectionDesc>{summaryMessage}</SectionDesc>
                {this.state.isPending && <Indicator />}
                {completedSuccessfully && <Svg className="summary-icon" path={svgs.apply} />}
              </SummaryBody>
            </SummarySection>

            {/** Displays an error message if one occurs while applying changes. */}
            {error && <AjaxError className="example-flyout-error" t={t} error={error} />}
            {
              /** If changes are not yet applied, show the buttons for applying changes and closing the flyout. */
              !changesApplied &&
              <BtnToolbar>
                <Btn svg={svgs.reconfigure} primary={true} disabled={isPending || itemCount === 0 } type="submit">{t('walkthrough.pageWithFlyout.flyouts.example.apply')}</Btn>
                <Btn svg={svgs.cancelX} onClick={onClose}>{t('walkthrough.pageWithFlyout.flyouts.example.cancel')}</Btn>
              </BtnToolbar>
            }
            {
              /**
               * If changes are applied, show only the close button.
               * Other text or component might be included here as well.
               * For example, you might provide a link to the detail page for a newly submitted job.
               * */
              !!changesApplied &&
              <BtnToolbar>
                <Btn svg={svgs.cancelX} onClick={onClose}>{t('walkthrough.pageWithFlyout.flyouts.example.close')}</Btn>
              </BtnToolbar>
            }
          </form>
      </Flyout>
    );
  }
}

src/walkthrough/components/pages/pageWithFlyout/flyouts フォルダーを src/components/pages/example フォルダーにコピーします。

ポップアップをページに追加する

ポップアップを追加するには、src/components/pages/example/basicPage.js を変更します。

components/shared からのインポートに Btn を追加し、svgsExampleFlyoutContainer のインポートを追加します。

import {
  AjaxError,
  ContextMenu,
  PageContent,
  RefreshBar,
  Btn
} from 'components/shared';
import { ExampleGrid } from './exampleGrid';
import { svgs } from 'utilities';
import { ExampleFlyoutContainer } from './flyouts/exampleFlyout';

closedFlyoutStateconst 定義を追加し、それをコンストラクターの state に追加します。

const closedFlyoutState = { openFlyoutName: undefined };

export class BasicPage extends Component {
  constructor(props) {
    super(props);
    this.state = { contextBtns: null, closedFlyoutState };
  }

BasicPage クラスに、次の関数を追加します。

  closeFlyout = () => this.setState(closedFlyoutState);

  openFlyout = (name) => () => this.setState({ openFlyoutName: name });

次の const 定義を、render 関数に追加します。

    const { openFlyoutName } = this.state;

    const isExampleFlyoutOpen = openFlyoutName === 'example';

ポップアップを開くボタンをコンテキスト メニューに追加します。

      <ContextMenu key="context-menu">
        {this.state.contextBtns}
        <Btn svg={svgs.reconfigure} onClick={this.openFlyout('example')}>{t('walkthrough.pageWithFlyout.open')}</Btn>
      </ContextMenu>,

いくつかのテキストとポップアップのコンテナーを、ページのコンテンツに追加します。

      <PageContent className="basic-page-container" key="page-content">
        {t('walkthrough.pageWithFlyout.pageBody')}
        { isExampleFlyoutOpen && <ExampleFlyoutContainer onClose={this.closeFlyout} /> }
        <RefreshBar refresh={fetchData} time={lastUpdated} isPending={isPending} t={t} />
        {!!error && <AjaxError t={t} error={error} />}
        {!error && <ExampleGrid {...gridProps} />}
      </PageContent>

ポップアップをテストする

まだ Web UI をローカルに実行していない場合は、リポジトリのローカル コピーのルートで次のコマンドを実行します。

npm start

前のコマンドは、https://localhost:3000/dashboard のローカルで UI を実行します。 [Example]\(例\) ページに移動して、[Open Flyout]\(ポップアップを開く\) をクリックします。

次の手順

この記事では、リモート監視ソリューション アクセラレータの Web UI のページの追加またはカスタマイズに使用できるリソースについて説明しました。

ページにポップアップを定義したので、次にリモート監視ソリューション アクセラレータ Web UI のダッシュボードにパネルを追加します。

リモート監視ソリューション アクセラレータの概念の詳細については、「 リモート監視アーキテクチャ」を参照してください。