演習 - geo 位置情報機能を使用して SPFx ACE を作成する

完了

この演習では、Viva Connectionsの地理位置情報機能を使用するプライマリ テキスト カード テンプレートを使用して、SharePoint Framework (SPFx) アダプティブ カード拡張機能 (ACE) を作成します。

実装するシナリオは、建物間を行き着くのに役立つシンプルなバージョンのキャンパス シャトル サービスです。 ACE はシャトルのダイバー向けです。 ドライバーは ACE を使用して旅行を予約し、乗客を迎えに行くか、目的地に乗客を引き渡す途中であることを示します。

前提条件

Viva Connections用の ACE を開発するには、テナントに Microsoft 365 テナント、SharePoint Online、Viva Connectionsを設定する必要があります。 テナントを準備するには、次のリソースを使用します。

ワークステーションに必要な開発者ツールもインストールする必要があります。

重要

ほとんどの場合、次のツールの最新バージョンをインストールすることをお勧めします。 ここに記載されているバージョンのリストは、このモジュールが発行され、最後にテストしたときに使用されたものです。

SharePoint リストを作成してデータを格納する

最初の手順では、各キャンパス シャトル ドライバーのデータを格納する新しい SharePoint リストを作成します。

ブラウザーで、この演習で作成するプロジェクトをテストする SharePoint サイトに移動します。

[ 新規 ] を選択し、使用可能なオプションから [一覧表示 ] を選択します。

新しいリスト エクスペリエンスのスクリーンショット。

[ リストの作成 ] ダイアログで、[ 空のリスト] を選択します。

一覧の [名前][キャンパス シャトル ] に設定し、[ 作成] を選択します。

ブラウザーが更新されて新しいリストが表示されたら、いくつかの列をリストに追加します。 [ 列の追加] を選択し、[ テキスト] を選択し、[ 次へ ] ボタンを選択します。 [ 列の作成 ] パネルで、次の値を入力し、[保存] を選択 します

  • 名前: OriginLocation
  • : 1 行のテキスト

次の値を使用してこのプロセスを繰り返して、さらにいくつかの列を一覧に追加します。

  • コラム:
    • 名前: DestinationName
    • : 1 行のテキスト
  • コラム:
    • 名前: DestinationLocation
    • : 1 行のテキスト
  • コラム:
    • 名前: 状態
    • : 選択
    • 選択肢:
      • 雇った
      • en route
      • 使用可能

ACE のデータを格納するリストを使用して、プロジェクトを作成できるようになりました。

SPFx プロジェクトを作成して準備する

コマンド プロンプトを開き、SPFx プロジェクトを作成するフォルダーに移動します。 その後、次のコマンドを実行して SharePoint Yeoman ジェネレーターを起動します。

yo @microsoft/sharepoint

表示されるプロンプトを完了するには、次のコマンドを使用します。

  • ソリューション名は何ですか?: AceCampusShuttle
  • 作成するクライアント側コンポーネントの種類:アダプティブ カード拡張機能
  • どのテンプレートを使用しますか?: プライマリ テキスト テンプレート
  • アダプティブ カード拡張機能の名前は何ですか?: Campus Shuttle

プロジェクトに必要なフォルダーをプロビジョニングした後、ジェネレーターは npm install を自動的に実行することで、すべての依存関係パッケージをインストールします。 NPM がすべての依存関係のダウンロードを完了したら、Visual Studio Code でプロジェクトを開きます。

サンプル データを追加する

作成する ACE を使用すると、シャトル ドライバーはリストから目的地を選択するか、マップ上のポイントを選択できます。

プロジェクトに新しいファイル ./src/adaptiveCardExtensions/campusShuttle/assets/campus_locations.json を作成し、場所オブジェクトの配列を追加します。 各場所には 、名前緯度経度 のプロパティが必要です。 または、フロリダ州ゲインズビルにあるフロリダ大学のいくつかの場所を含むファイルに、次の JSON を貼り付米国。

[
  { "title": "UF: Reitz Student Union", "latitude": 29.6463258, "longitude": -82.3499756 },
  { "title": "UF: The Hub", "latitude": 29.648018, "longitude": -82.345664 },
  { "title": "UF: Department of Computer and Information Science and Engineering", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: Materials Science and Engineering", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: Turlington Hall", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: McCarty Hall A", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: Peabody Hall", "latitude": 29.6502915, "longitude": -82.3433807 },
  { "title": "UF: Norman Hall", "latitude": 29.6486165, "longitude": -82.3398393 },
  { "title": "UF: Warrington College of Business", "latitude": 29.65093, "longitude": -82.3402091 },
  { "title": "UF: Mechanical and Aerospace Engineering Building A", "latitude": 29.6436917, "longitude": -82.3478054 },
  { "title": "UF: New Physics Building (NPB)", "latitude": 29.6439734, "longitude": -82.3506927 },
  { "title": "UF: Murphree Hall", "latitude": 29.6508923, "longitude": -82.3480633 }
]

SharePoint REST API サービス ヘルパーを追加する

次に、SharePoint REST サービスをプロジェクトに追加して、シャトル ドライバー データを格納するために作成した SharePoint リストへのすべての読み取りと書き込みを処理します。

プロジェクトに新しいファイル ./src/adaptiveCardExtensions/campusShuttle/sp.service.ts を作成し、次のコードを追加します。

import { AdaptiveCardExtensionContext } from '@microsoft/sp-adaptive-card-extension-base';
import { SPHttpClient } from '@microsoft/sp-http'

export const STATUS_HIRED = 'hired';
export const STATUS_ENROUTE = 'en route';
export const STATUS_AVAILABLE = 'available';

export interface ILocation {
  latitude: number;
  longitude: number;
}

export interface IListItem {
  ['@odata.type']?: string;
  Id?: string;
  Title: string;
  Status: string;
  OriginLocation?: string | ILocation;
  DestinationName?: string;
  DestinationLocation?: string | ILocation;
}

export const fetchListItem = async (spContext: AdaptiveCardExtensionContext, listId: string): Promise<IListItem> => {
  if (!listId) { return Promise.reject('No listId specified.'); }

  const listApiUrl = `${spContext.pageContext.web.absoluteUrl}/_api/web/lists/GetById(id='${listId}')`;
  const user = spContext.pageContext.user.loginName;

  const response: { value: IListItem[] } = await (await spContext.spHttpClient.get(
    `${listApiUrl}/items/?$select=Id,Title,Status,OriginLocation,DestinationName,DestinationLocation&$filter=Title eq '${user}'&$top=1`,
    SPHttpClient.configurations.v1
  )).json();

  if (response.value.length === 0) { return Promise.resolve(undefined); }

  const convertedTrip = response.value[0];

  if (convertedTrip) {
    const origin = convertedTrip.OriginLocation as string;
    convertedTrip.OriginLocation = <ILocation>{
      latitude: Number(origin.split(',')[0]),
      longitude: Number(origin.split(',')[1])
    };
  }
  if (convertedTrip) {
    const destination = convertedTrip.DestinationLocation as string;
    convertedTrip.DestinationLocation = <ILocation>{
      latitude: Number(destination.split(',')[0]),
      longitude: Number(destination.split(',')[1])
    };
  }

  return Promise.resolve(convertedTrip);
}

const getItemEntityType = async (spContext: AdaptiveCardExtensionContext, listApiUrl: string): Promise<string> => {
  const response: { ListItemEntityTypeFullName: string } = await (await spContext.spHttpClient.get(
    `${listApiUrl}?$select=ListItemEntityTypeFullName`,
    SPHttpClient.configurations.v1
  )).json();

  return response.ListItemEntityTypeFullName;
}

const createListItem = async (
  spContext: AdaptiveCardExtensionContext,
  listApiUrl: string,
  listItem: IListItem): Promise<void> => {

  listItem['@odata.type'] = await getItemEntityType(spContext, listApiUrl);

  await spContext.spHttpClient.post(
    `${listApiUrl}/items`,
    SPHttpClient.configurations.v1,
    {
      headers: {
        'ACCEPT': 'application/json; odata.metadata=none',
        'CONTENT-TYPE': 'application/json'
      },
      body: JSON.stringify(listItem)
    }
  );

  return Promise.resolve();
}

export const upsertListItem = async (spContext: AdaptiveCardExtensionContext, listId: string, listItem: IListItem): Promise<void> => {
  if (!listId) { return Promise.reject('No listId specified.'); }

  const listApiUrl = `${spContext.pageContext.web.absoluteUrl}/_api/web/lists/GetById(id='${listId}')`;

  const originLocationObj = (listItem.OriginLocation as ILocation);
  listItem.OriginLocation = `${originLocationObj.latitude},${originLocationObj.longitude}`;
  const destinationLocationObj = (listItem.DestinationLocation as ILocation);
  listItem.DestinationLocation = `${destinationLocationObj.latitude},${destinationLocationObj.longitude}`;

  if (!listItem['@odata.type']) { return createListItem(spContext, listApiUrl, listItem); }

  await spContext.spHttpClient.post(
    `${listApiUrl}/items(${listItem.Id})`,
    SPHttpClient.configurations.v1,
    {
      headers: { 'IF-MATCH': '*', 'X-HTTP-METHOD': 'MERGE' },
      body: JSON.stringify(<IListItem>{
        Title: listItem.Title,
        Status: listItem.Status,
        OriginLocation: listItem.OriginLocation,
        DestinationName: listItem.DestinationName,
        DestinationLocation: listItem.DestinationLocation
      })
    }
  );

  return Promise.resolve();
}

export const deleteListItem = async (spContext: AdaptiveCardExtensionContext, listId: string, listItemId: number): Promise<void> => {
  if (!listId) { return Promise.reject('No listId specified.'); }
  if (!listItemId) { return Promise.reject('No listItemId specified.'); }

  const listApiUrl = `${spContext.pageContext.web.absoluteUrl}/_api/web/lists/GetById(id='${listId}')`;

  await spContext.spHttpClient.post(
    `${listApiUrl}/items(${listItemId})`,
    SPHttpClient.configurations.v1,
    {
      headers: { 'IF-MATCH': '*', 'X-HTTP-METHOD': 'DELETE' }
    }
  );
}

このサービスは、プロジェクト全体で使用する次のものをエクスポートします。

  • 状態オプションの 3 つの定数 ():
    • STATUS_AVAILABLE
    • STATUS_ENROUTE
    • STATUS_HIRED
  • fetchListItem(): このメソッドは、現在サインインしているドライバー レコード (存在する場合) を取得します。
  • upsertListItem(): このメソッドは、新しいドライバー レコードを作成するか、既存のドライバー レコードを更新します。
  • deleteListItem(): このメソッドは、ドライバー レコードが旅行中に長い場合に削除します。

プロジェクトを初期化する

プロジェクトにコア依存関係がいくつか追加されたので、ACE が最初にページに読み込まれるときに、いくつかのコア機能の初期化を実装してみましょう。 これには、ACE の状態を構成し、ドライバートリップの詳細を含むリストの ID をユーザーが設定できるようにする必要があります。

ユーザーが SharePoint リスト ID を設定できるように ACE を更新する

ファイル ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts で ACE クラスを見つけて、VS Code で開きます。

ICampusShuttleAdaptiveCardExtensionProps インターフェイスを見つけて、listId プロパティを追加して、ドライバーの状態レコードを含む SharePoint リストの ID を格納します。

export interface ICampusShuttleAdaptiveCardExtensionProps {
  title: string;
  listId: string;
}

ファイル ./src/adaptiveCardExtensions/campusShuttle/CampusShuttlePropertyPane.tsを見つけて開きます。 groupFields配列に新しいPropertyPaneTextFieldを追加して、ドライバーの状態レコードを含むリストの ID を設定するオプションを追加します。

groupFields: [
  PropertyPaneTextField('title', {
    label: strings.TitleFieldLabel
  }),
  PropertyPaneTextField('listId', {
    label: 'List ID (GUID)'
  })
]

最後に、 CampusShuttleAdaptiveCardExtension.ts ファイルに戻り、次のメソッドを CampusShuttleAdaptiveCardExtension クラスに追加します。 SPFx ランタイムは、プロパティ ウィンドウのプロパティの値が変更されると、このイベントを発生させます。 ドライバー レコードが見つかった場合は、ACE でリストの ID の変更を使用して ACE の状態を初期化します。

protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
  if (propertyPath === 'listId' && newValue !== oldValue) {
    if (newValue) {
      (async () => {
        const trip = await fetchListItem(this.context, this.properties.listId);
        if (trip) { this.setState({ currentTrip: trip }); }
      })();
    }
  }
}

ACE 状態と初期カード ビューを更新する

ファイル内の既存の import ステートメントの後に、次のimport ステートメントを追加します。

import {
  IListItem,
  fetchListItem,
  STATUS_AVAILABLE
} from './sp.service';

状態インターフェイスの ICampusShuttleAdaptiveCardExtensionState を見つけて、次のコードに示すように currentTrip プロパティを追加します。

export interface ICampusShuttleAdaptiveCardExtensionState {
  currentTrip: IListItem;
}

既存の onInit() メソッドで state プロパティを初期化します。 既存の this.state = { }; を次のコードに置き換えて、状態を現在のドライバーのプレースホルダートリップに設定します。

this.state = {
  currentTrip: {
    Title: this.context.pageContext.user.loginName,
    Status: STATUS_AVAILABLE
  }
};

次に、 onInit() メソッドに次のコードを追加します。 return Promise.resolve(); ステートメントの直前に、現在のドライバーのトリップ レコードを SharePoint リストから取得します。 一致する旅行が見つかった場合、ACE の状態がこの旅行に更新され、状態を初期化するときに作成した空の既定の旅行が上書きされます。

if (this.properties.listId) {
  const trip = await fetchListItem(this.context, this.properties.listId);
  if (trip) { this.setState({ currentTrip: trip }); }
}

このコードでは await キーワード (keyword) を使用しますが、onInit() メソッドシグネチャはPromiseを返しますが、必要なasync キーワード (keyword)はありません。 onInit() メソッド宣言を更新して、次のキーワード (keyword)を含めます。

public async onInit(): Promise<void> { .. }

既存の QuickView を削除し、最初の CardView を更新します

ACE をテストする前の最後の手順は、現在の QuickView を削除することです。 後で、ACE に複数の新しいクイック ビューを追加します。

まず、 CampusShuttleAdaptiveCardExtension.ts ファイルから次の行を削除します。

  1. 次の import ステートメントを削除します。

    import { QuickView } from './quickView/QuickView';
    
  2. QuickView ID の export 宣言を削除します。

    export const QUICK_VIEW_REGISTRY_ID: string = 'CampusShuttle_QUICK_VIEW';
    
  3. CampusShuttleAdaptiveCardExtension クラスの onInit() メソッドで、QuickView を登録する次のステートメントを削除します。

    this.quickViewNavigator.register(QUICK_VIEW_REGISTRY_ID, () => new QuickView());
    
  4. プロジェクトから次のファイルを削除します。

    • ./src/adaptiveCardExtensions/campusShuttle/quickView/template/QuickViewTemplate.json
    • ./src/adaptiveCardExtensions/campusShuttle/quickView/QuickView.ts

次に、CardView: ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts を見つけて開き、それに次の変更を加えます。

  1. @microsoft/sp-adaptive-card-extension-base パッケージの値を参照する既存の import ステートメントを見つけて、次の参照を削除します。

    • IExternalLinkCardAction
    • IQuickViewCardAction
  2. CampusShuttleAdaptiveCardExtension モジュールの値を参照する既存のimport ステートメントを見つけて、QUICK_VIEW_REGISTRY_ID定数への参照を削除します。

  3. 次の import ステートメントを、既存の import ステートメントの後に追加します:

    import { STATUS_AVAILABLE } from '../sp.service';
    
  4. cardButtons() アクセサー メンバーの内容を次の switch ステートメントに置き換えます。 ACE に新しい機能を追加するときに、この演習全体を通じてこの switch ステートメントを更新します。

public get cardButtons(): [ICardButton] | [ICardButton, ICardButton] | undefined {
  switch (this.state.currentTrip.Status) {
    default:
      return undefined;
      break;
  }
}
  1. data() アクセサー メンバーを更新して、現在のカードに使用されるプロパティを返します。
public get data(): IPrimaryTextCardParameters {
  return {
    primaryText: strings.PrimaryText,
    description: (this.state.currentTrip.Status === STATUS_AVAILABLE)
      ? `available for hire`
      : `TODO`,
    title: this.properties.title
  };
}
  1. CardView にボタンがないため、既存の onCardSelection() アクセサー メンバーを削除します。

ACE をテストする

これで、ACE の初期状態をテストする準備ができました。

コンソールで、次のステートメントを実行します。

gulp serve --nobrowser

ブラウザーで、ドライバー レコードを格納するためにリストを作成したのと同じサイトの SharePoint ホストワークベンチに移動します。 たとえば、リスト URL が https://contoso.sharepoint.com/sites/MSLearningTeam/Lists/Campus%20Shuttle/AllItems.aspxされている場合、ホストされているワークベンチの URL は https://contoso.sharepoint.com/sites/MSLearningTeam/_layouts/15/workbench.aspx

[ + ] アイコンを選択し、ツールボックスから [Campus Shuttle ] を選択します。

SPFx ツールボックスのスクリーンショット。

ACE コンポーネントの上にマウス ポインターを合わせ、鉛筆アイコンを選択してプロパティ ウィンドウを開きます。

ACE の編集エクスペリエンスのスクリーンショット。

[リスト ID] ボックスに SharePoint リストの ID を 入力し、右上隅にある [X ] アイコンを選択してプロパティ ウィンドウを閉じます。

ヒント

リストの ID は、リストの設定ページ URL から取得できます。

まずリストを参照し、スイート バーの歯車アイコンを選択してから、[ リスト設定 ] リンクを選択します。

リスト設定のページのクエリ文字列には、List=%7B93f11b8b-6201-4199-b263-3ca78408a73b%7Dなどの List プロパティが含まれています。 これは、で囲まれた GUID を含む URL でエンコードされた文字列です。 %7B プレフィックスとサフィックス%7D削除して、リストの ID を取得します。 たとえば、このリスト ID は 93f11b8b-6201-4199-b263-3ca78408a73b

リスト設定ページを取得する方法のスクリーンショット。

一覧にレコードがまだないため、ACE のレンダリングに変更があることに気付くことはありません。

この時点で、最小限のプロジェクトが動作しています。 QuickViews を使用して ACE への対話機能の追加を開始できます。

QuickViews を使用して旅行を作成する機能を追加する

次に、現在のユーザーが ACE を使用して新しい旅行を追加できるようにする機能を実装します。 旅行を作成するときは、次の 3 つを設定する必要があります。

  • 旅行の配信元/開始場所
  • 旅行の目的地の場所
  • シャトルドライバーが出発地から乗客をピックアップする途中にある場合、または乗客をピックアップして目的地に向かう途中にある場合

これを実装するには、複数の QuickView を作成し、Viva Connectionsの ACE の地理的位置機能を使用します。

StartTrip QuickView を作成する

まず、./src/adaptiveCardExtensions/campusShuttle/quickView/template フォルダーに新しいファイル StartTripCard.jsonを作成し、次の JSON を追加します。 これにより、アダプティブ カードを使用して QuickView の内容が設定されます。

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.5",
  "body": [
    {
      "type": "TextBlock",
      "text": "Start a trip",
      "size": "Large",
      "weight": "Bolder"
    },
    {
      "type": "TextBlock",
      "text": "Select trip status:",
      "size": "medium",
      "weight": "Bolder"
    },
    {
      "id": "tripType",
      "type": "Input.ChoiceSet",
      "value": "$trip.Status",
      "choices": [
        {
          "title": "en route to pickup",
          "value": "en route"
        },
        {
          "title": "starting trip",
          "value": "hired"
        }
      ]
    },
    {
      "type": "TextBlock",
      "text": "Set trip details:",
      "size": "medium",
      "weight": "Bolder"
    }
  ],
  "actions": [
    {
      "id": "originLocation",
      "type": "Action.Submit",
      "title": "(1) Select trip origin from map"
    },
    {
      "id": "destinationLocation",
      "type": "Action.Submit",
      "title": "(2) Select / set trip destination"
    },
    {
      "id": "save",
      "type": "Action.Submit",
      "title": "Save trip",
      "style": "positive"
    }
  ]
}

次に、./src/adaptiveCardExtensions/campusShuttle/quickView フォルダーにファイル StartTrip.tsを作成します。 このファイルには、QuickView を実装するクラスが含まれます。

このファイルに次のコードを追加します。

import {
  ISPFxAdaptiveCard,
  BaseAdaptiveCardView,
  IActionArguments
} from '@microsoft/sp-adaptive-card-extension-base';
import * as strings from 'CampusShuttleAdaptiveCardExtensionStrings';
import {
  ICampusShuttleAdaptiveCardExtensionProps,
  ICampusShuttleAdaptiveCardExtensionState
} from '../CampusShuttleAdaptiveCardExtension';

import { IListItem, upsertListItem } from '../sp.service';

export interface IStartTripData {
  title: string;
  trip: IListItem;
}

export class StartTrip extends BaseAdaptiveCardView<
  ICampusShuttleAdaptiveCardExtensionProps,
  ICampusShuttleAdaptiveCardExtensionState,
  IStartTripData
> {

  public get data(): IStartTripData {
    return {
      title: strings.Title,
      trip: this.state.currentTrip
    };
  }

  public get template(): ISPFxAdaptiveCard {
    return require('./template/StartTripCard.json');
  }

  public onAction(action: IActionArguments): void {
    if (action.type === 'Submit') {
      if (action.data.tripType) {
        const trip = this.state.currentTrip;
        trip.Status = action.data.tripType;
        this.setState({ currentTrip: trip });
      }

      if (action.id === 'originLocation') {
        // TODO QuickView originLocation
      } else if (action.id === 'destinationLocation') {
        // TODO QuickView destinationLocation
      } else if (action.id === 'save') {
        (async () => {
          await upsertListItem(this.context, this.properties.listId, this.state.currentTrip);
          // TODO QuickView save
        })();
      }
    }
  }

}

このファイルの StartTrip クラスには、次の 3 つのメンバーが含まれています。

  • data(): このアクセサー メンバーは、プロパティを QuickView の実装に使用されるアダプティブ カードにバインドするために使用されるアダプティブ カード レンダリング エンジンにオブジェクトを返します。
  • template(): このアクセサー メンバーは、アダプティブ カード定義を含む JSON オブジェクトを返します。
  • onAction(): このメソッドは、アダプティブ カードで特定のアクションが発生したときに呼び出されます。 この時点で、コードは旅行の種類 (途中 | hired) の値を保存するだけで、プロジェクトに追加するより多くの QuickView カードのプレースホルダーが含まれています。

プロジェクトに含まれる QuickView の参照を簡略化するには、次のコード を含./src/adaptiveCardExtensions/campusShuttle/quickView フォルダーに新しいファイル index.tsを追加します。

export * from './StartTrip';

StartTrip クイック ビューを登録して参照する

これを新しい QuickView を使用するには、ACE の QuickView ナビゲーターに登録する必要があります。 ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts ファイルを開きます。

既存の import ステートメントの後に次の import ステートメントを追加して、作成した新しい QuickView をインポートします。

import {
  StartTrip
} from './quickView';

CampusShuttleAdaptiveCardExtension クラス宣言の直前に定数を見つけて、次の宣言を追加します。

export const QUICK_VIEW_START_TRIP_REGISTRY_ID: string = 'CampusShuttle_StartTrip_QUICK_VIEW';

次に、クラスの onInit() メソッドCampusShuttleAdaptiveCardExtensionで、次の行を見つけます。

this.cardNavigator.register(CARD_VIEW_REGISTRY_ID, () => new CardView());

次の行を追加して、StartTrip QuickView を QuickView ナビゲーターに登録します。

this.quickViewNavigator.register(QUICK_VIEW_START_TRIP_REGISTRY_ID, () => new StartTrip());

CardView に StartTrip クイック ビューを追加する

最後の手順では、QuickView を CardView に追加して使用します。 VS Code で次のファイルを見つけて開きます: ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts

ACE クラス宣言を含むファイルからプロパティと状態インターフェイスをインポートする import ステートメントを見つけます。 StartTrip QuickView の ID を含む追加した定数を追加します。

import {
  ICampusShuttleAdaptiveCardExtensionProps,
  ICampusShuttleAdaptiveCardExtensionState,
  QUICK_VIEW_START_TRIP_REGISTRY_ID   // << add this
} from '../CampusShuttleAdaptiveCardExtension';

次に、cardButtons() アクセサーの switch ステートメントで、既存のdefaultの前に case ステートメントを追加して、現在のドライバーの状態が使用可能なときに旅行を予約するためのボタンを表示します。

switch (this.state.currentTrip.Status) {
  case STATUS_AVAILABLE:
    return [{
      title: 'Book a Trip',
      action: {
        type: 'QuickView',
        parameters: { view: QUICK_VIEW_START_TRIP_REGISTRY_ID }
      }
    }];
    break;
  default:
    return undefined;
    break;
}

ACE をテストして、QuickView が動作していることを確認します。 以前にローカル Web サーバーを停止した場合は、コンソールで次のコマンドを実行して再起動します。

gulp serve --nobrowser

SharePoint でホストされているワークベンチに移動して、Campus Shuttle ACE を確認します。

編集モードでレンダリングされた ACE のスクリーンショット。

[CardView で 旅行を予約 する] ボタンに注目してください。 上部のナビゲーションの右上セクションにある [プレビュー ] リンクを選択してテストします。 このページでは、編集モードからボタンを選択できる表示モードに切り替わります。

プレビュー モードまたは表示モードでレンダリングされた ACE のスクリーンショット。

StartTrip QuickView の機能を実装してみましょう。

StartTrip QuickView に機能を追加する

これで、StartTrip クイック ビューで使用される 3 つのクイック ビューを追加します。 1 つは旅行の出発地の設定を処理し、もう 1 つは旅行の目的地の選択または設定を処理し、最後の 1 つは旅行を保存するときに確認通知として機能します。

  • 次のコードを 使用 して、 ./src/adaptiveCardExtensions/campusShuttle/quickView/template フォルダーに新しいファイル SetOriginCard.jsonを追加します。

    {
      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "large",
          "text": "${title}"
        },
        {
          "type": "TextBlock",
          "text": "${description}",
          "wrap": true
        }
      ],
      "actions": [
        {
          "id": "originLocation",
          "type": "VivaAction.GetLocation",
          "title": "Select location on the map",
          "parameters": {
            "chooseLocationOnMap": true
          }
        }
      ]
    }
    

    このアダプティブ カードの 1 つのアクションが VivaAction.GetLocation 型に設定されていることに注意してください。 これにより、ユーザーはデバイスから場所を選択し、座標を返すように求められます。

  • 次のコードを使用して、./src/adaptiveCardExtensions/campusShuttle/quickView フォルダーに新しいファイル SetOrigin.tsを追加して、SetOrigin QuickView を実装します。

    import {
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView,
      IGetLocationActionArguments
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
    
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import { ILocation, IListItem } from '../sp.service';
    
    export interface ISetOriginData {
      title: string;
      description: string;
      trip: IListItem;
    }
    
    export class SetOrigin extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      ISetOriginData
    > {
      public get data(): ISetOriginData {
        return {
          title: 'Set trip starting location',
          description: 'Select the trip origin location by selecting it on the map.',
          trip: this.state.currentTrip
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/SetOriginCard.json');
      }
    
      public onAction(action: IGetLocationActionArguments): void {
        if (action.type === 'VivaAction.GetLocation'){
    
          const currentTrip = this.state.currentTrip;
          currentTrip.OriginLocation = <ILocation> {
            latitude: action.location.latitude,
            longitude: action.location.longitude
          };
    
          this.setState({ currentTrip: currentTrip });
    
          this.quickViewNavigator.pop();
        }
      }
    }
    

    このコードは、 onAction() イベント ハンドラー内で、 VivaAction.GetLocation がアダプティブ カードによって送信されたときに、選択した場所を取得する方法に注目してください。 トリップで選択した場所を設定し、ACE の状態で trip オブジェクトを更新します。 this.quickViewNavigator.pop()を最後に呼び出すと、この QuickView が QuickView スタックから削除され、スタック内の次の QuickView の再レンダリングがトリガーされます。

次に、宛先の場所を設定するための同様の QuickView を実装します。

  • 次のコードを 使用して、 新しいファイル SetDestinationCard.json を ./src/adaptiveCardExtensions/campusShuttle/quickView/template フォルダーに追加します。

    {
      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "text": "${title}"
        },
        {
          "type": "TextBlock",
          "text": "${description}"
        },
        {
          "type": "TextBlock",
          "text": "Select a known location..."
        },
        {
          "id": "knownDestinationSelection",
          "type": "Input.ChoiceSet",
          "choices": [
            {
              "$data": "${campus_locations}",
              "title": "${title}",
              "value": "${latitude},${longitude}"
            }
          ]
        },
        {
          "type": "TextBlock",
          "text": "... or select a specific location on the map:"
        }
      ],
      "actions": [
        {
          "id": "destinationLocation",
          "type": "VivaAction.GetLocation",
          "title": "Select trip destination from map",
          "parameters": { "chooseLocationOnMap": true }
        },
        {
          "id": "save",
          "type": "Action.Submit",
          "title": "Save destination location",
          "style": "positive"
        }
      ]
    }
    

    このアダプティブ カードは、ユーザーがマップ上の場所を選択するか、定義済みの場所の一覧から選択できるように、配信元の場所に使用されるカードと似ています。 これらの定義済みの場所は、 ./src/adaptiveCardExtensions/campusShuttle/assets/campus_locations.json ファイルにあります。

    アダプティブ カードには、別の送信アクション ボタンも含まれています。 設定された配信元 QuickView とは異なり、このボタンは、ユーザーが旅行先を選択するための 2 つのオプションを持つので、設定された目的地 QuickView を閉じるのに使用されます。

  • 次のコードを使用して、./src/adaptiveCardExtensions/campusShuttle/quickView フォルダーに新しいファイル SetDestination.tsを追加して、SetDestination QuickView を実装します。

    import {
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView,
      IActionArguments,
      IGetLocationActionArguments
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import { ILocation, IListItem } from '../sp.service';
    
    import { sortBy } from '@microsoft/sp-lodash-subset';
    
    interface ICampusLocations {
      title: string;
      latitude: number;
      longitude: number;
    }
    
    export interface ISetDestinationData {
      title: string;
      description: string;
      campus_locations: ICampusLocations[];
      trip: IListItem;
    }
    
    const LOCATIONS = require('../assets/campus_locations.json');
    
    export class SetDestination extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      ISetDestinationData
    > {
      public get data(): ISetDestinationData {
        return {
          title: 'Set trip destination location',
          description: 'Pick from a list of known locations, or set the destination by selecting it on the map.',
          campus_locations: sortBy(LOCATIONS, (l) => l.title),
          trip: this.state.currentTrip
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/SetDestinationCard.json');
      }
    
      public onAction(action: IActionArguments | IGetLocationActionArguments): void {
        const currentTrip = this.state.currentTrip;
    
        // if picked a location on the map...
        if (action.type === 'VivaAction.GetLocation') {
          currentTrip.DestinationLocation = <ILocation>{
            latitude: action.location.latitude,
            longitude: action.location.longitude
          };
          this.setState({ currentTrip: currentTrip });
        } else if (action.type === 'Submit' && action.id === 'save') {
          // else, check if picked location from dropdown and save it
          if (action.data.knownDestinationSelection) {
            currentTrip.DestinationLocation = <ILocation>{
              latitude: Number(action.data.knownDestinationSelection.split(',')[0]),
              longitude: Number(action.data.knownDestinationSelection.split(',')[1])
            };
    
           const selectedLocation = LOCATIONS.filter((knownLocation: any) => (
              knownLocation.latitude === (currentTrip.DestinationLocation as ILocation).latitude
              && knownLocation.longitude === (currentTrip.DestinationLocation as ILocation).longitude
            ))[0];
            currentTrip.DestinationName = selectedLocation.title;
          }
          this.setState({ currentTrip: currentTrip });
          this.quickViewNavigator.pop();
        }
      }
    
    }
    

最後の手順では、保存確認 QuickView をプロジェクトに追加します。

  • 次のコードを 使用 して、 ./src/adaptiveCardExtensions/campusShuttle/quickView/template フォルダーに新しいファイル SaveTripCard.jsonを追加します。

    {
      "schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [{
        "type": "TextBlock", "text": "${title}"
      }],
      "actions": [{
        "type": "Action.Submit",
        "id": "close",
        "title": "Close"
      }]
    }
    
  • 次のコードを使用して、./src/adaptiveCardExtensions/campusShuttle/quickView フォルダーに新しいファイル SaveTrip.tsを追加して、SaveTrip QuickView を実装します。

    import {
      BaseAdaptiveCardView,
      IActionArguments,
      ISPFxAdaptiveCard
     } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    export interface ISaveTripData {
      title: string;
    }
    
    export class SaveTrip extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      ISaveTripData
    > {
      public get data(): ISaveTripData {
        return {
          title: 'Trip saved successfully.'
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/SaveTripCard.json');
      }
    
      public onAction(action: IActionArguments): void {
        if (action.id === 'close') {
          this.quickViewNavigator.close();
        }
      }
    }
    

これら 3 つの新しい QuickView を使用するには、それらを登録する必要があります。

  1. ./src/adaptiveCardExtensions/campusShuttle/quickView/index.ts ファイルを開き、新しい QuickView をエクスポートします。

    export * from './StartTrip';
    export * from './SetOrigin';      // << add
    export * from './SetDestination'; // << add
    export * from './SaveTrip';       // << add
    
  2. ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts ファイルを開きます。

    1. 追加した既存の import ステートメントを更新して 、StartTrip QuickView をインポートして、次の 3 つの新しいクイック ビューを参照します。

      import {
        StartTrip,
        SetOrigin,
        SetDestination,
        SaveTrip
      } from './quickView';
      
    2. CardView と QuickView の ID を宣言する定数を見つけ、新しい QuickView に次の ID を追加します。

      export const QUICK_VIEW_SET_ORIGIN_REGISTRY_ID: string = 'CampusShuttle_SetOrigin_QUICK_VIEW';
      export const QUICK_VIEW_SET_DESTINATION_REGISTRY_ID: string = 'CampusShuttle_SetDestination_QUICK_VIEW';
      export const QUICK_VIEW_SAVE_TRIP_REGISTRY_ID: string = 'CampusShuttle_SaveTrip_QUICK_VIEW';
      
    3. CampusShuttleAdaptiveCardExtension クラスの onInit() メソッド内で、StartTrip QuickView を登録した this.quickViewNavigator.register() ステートメントを既存の呼び出しの後に次のコードを追加します。

      this.quickViewNavigator.register(QUICK_VIEW_SET_ORIGIN_REGISTRY_ID, () => new SetOrigin());
      this.quickViewNavigator.register(QUICK_VIEW_SET_DESTINATION_REGISTRY_ID, () => new SetDestination());
      this.quickViewNavigator.register(QUICK_VIEW_SAVE_TRIP_REGISTRY_ID, () => new SaveTrip());
      

最後の手順では、QuickView を既存の StartTrip QuickView に接続します。

  1. ./src/adaptiveCardExtensions/campusShuttle/quickView/StartTrip.ts ファイルを見つけて開きます。

  2. CampusShuttleCopilotAdaptiveCardExtension モジュール内のプロパティ インターフェイスと状態インターフェイスを参照する既存のimport ステートメントを見つけます。 これを更新して、3 つの新しい QuickView の 3 つの定数をインポートします。

    import {
      ICampusShuttleCopilotAdaptiveCardExtensionProps,
      ICampusShuttleCopilotAdaptiveCardExtensionState,
      QUICK_VIEW_SET_ORIGIN_REGISTRY_ID,
      QUICK_VIEW_SET_DESTINATION_REGISTRY_ID,
      QUICK_VIEW_SAVE_TRIP_REGISTRY_ID
    } from '../CampusShuttleAdaptiveCardExtension';
    
  3. onAction() メソッドのコメント // TODO QuickView originLocationを次のように置き換えて、SetOrigin QuickView を実装します。

    this.quickViewNavigator.push(QUICK_VIEW_SET_ORIGIN_REGISTRY_ID);
    
  4. onAction() メソッドのコメント // TODO QuickView destinationLocationを次に置き換えて、SetDestination QuickView を実装します。

    this.quickViewNavigator.push(QUICK_VIEW_SET_DESTINATION_REGISTRY_ID);
    
  5. onAction() メソッドのコメント // TODO QuickView saveを次のように置き換えて、SaveTrip QuickView を実装します。

    this.quickViewNavigator.push(QUICK_VIEW_SAVE_TRIP_REGISTRY_ID);
    

これらの呼び出しのたびに、QuickView がナビゲーターに プッシュ されていることに注意してください。 これにより、スタック上の新しい項目を使用して QuickView の再レンダリングがトリガーされます。 以前は、QuickView をスタックからポップしていたリコール。

最後の手順では、旅行が予約されたときに CardView の表示を更新します。

  1. ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts ファイルを見つけて開きます。

  2. 既存の import ステートメント ( import { STATUS_AVAILABLE } from '../sp.service';) を次のコードに置き換えます。

    import {
      ILocation,
      STATUS_AVAILABLE,
      STATUS_ENROUTE,
      STATUS_HIRED
    } from '../sp.service';
    
  3. cardButtons() メソッドの switch ステートメントを次のコードに更新します。

    switch (this.state.currentTrip.Status) {
      case STATUS_AVAILABLE:
        return [{
          title: 'Book a Trip',
          action: {
            type: 'QuickView',
            parameters: { view: QUICK_VIEW_START_TRIP_REGISTRY_ID }
          }
        }];
        break;
      case STATUS_ENROUTE:
        return [
          {
            title: 'View pickup location',
            action: {
              type: 'VivaAction.ShowLocation',
              parameters: {
                locationCoordinates: {
                  latitude: (this.state.currentTrip.OriginLocation as ILocation).latitude,
                  longitude: (this.state.currentTrip.OriginLocation as ILocation).longitude
                }
              }
            }
          }
        ];
        break;
      case STATUS_HIRED:
        return [
          {
            title: 'View dropoff location',
            action: {
              type: 'VivaAction.ShowLocation',
              parameters: {
                locationCoordinates: {
                  latitude: (this.state.currentTrip.DestinationLocation as ILocation).latitude,
                  longitude: (this.state.currentTrip.DestinationLocation as ILocation).longitude
                }
              }
            }
          }
        ];
        break;
      default:
        return undefined;
        break;
    }
    

    これらの変更により、現在のシャトル ドライバーの状態に応じて、異なるボタンとテキストが条件付きで表示されます。 現在、CardView のアクション VivaAction.ShowLocation を使用して、指定した配信元と宛先の場所を表示していることに注意してください。

  4. 最後に、data() メソッドの return ステートメントを次のコードに更新します。

    return {
      primaryText: strings.PrimaryText,
      description: (this.state.currentTrip.Status === STATUS_AVAILABLE)
        ? `available for hire`
        : (this.state.currentTrip.Status === STATUS_ENROUTE)
          ? `Booked - ${STATUS_ENROUTE} to pickup...`
          : (this.state.currentTrip.DestinationName)
            ? `Hired - driving passenger to ${this.state.currentTrip.DestinationName}...`
            : `Hired - driving passenger to destination...`,
      title: this.properties.title
    };
    

    これにより、シャトル ドライバーの乗車状態に基づいて条件付きメッセージが変更されることに注意してください。

テスト 旅行作成エクスペリエンス

この時点で、ブラウザーで完全な旅行作成エクスペリエンスをテストできます。

以前にローカル Web サーバーを停止した場合は、コンソールで次のコマンドを実行して再起動します。

gulp serve --nobrowser

SharePoint でホストされているワークベンチに移動して、Campus Shuttle ACE を表示します。

カード サイズが [中] に設定されている場合、ACE は CardView に 1 つのボタンのみを表示します。 ページが編集モードの間にプロパティ ウィンドウを開き、カードのサイズを [大] に変更して、両方のボタンが CardView に表示されるようにします。

次に、ツール バーの右上にある [プレビュー ] ボタンを選択します。

まず、最初の CardView で [ 旅行の予約 ] ボタンを選択します。 これは、以前にテストした [旅行の開始] クイック ビューを表示します。

(1) [マップから旅行の配信元を選択] ボタンを選択して、SetOrigin QuickView を読み込みます。 次に、[ マップ上の場所の選択 ] ボタンを選択します。 ブラウザーに位置情報へのアクセス権を付与していない場合は、アクセスを求めるメッセージが表示されます。 VivaAction.GetLocation アクションを機能させるには、この要求を承認する必要があります。

場所へのアクセスを許可するブラウザー プロンプトのスクリーンショット。

ブラウザーに位置情報へのアクセスを許可すると、マップを含むダイアログが表示されます。 乗車の乗車場所の場所にマップを中央揃えし、乗車を選択して [ 場所の共有 ] ボタンを選択します。

乗車ピックアップの配信元の場所を選択しているスクリーンショット。

(2) [旅行先の選択/設定] ボタンを選択して、SetDestination QuickView を読み込みます。 今回は、ドロップダウン ボックスで既知の場所の 1 つを選択し、[ 保存先の保存 ] ボタンを選択します。

旅行の目的地の場所を選択するスクリーンショット。

最後に、乗車状態を選択して 乗車に向かう途中で 、[ 旅行の保存 ] ボタンを選択します。

保存の確認 QuickView を示すスクリーンショット。

旅行が保存された状態で、現在のコンテキストに基づいて CardView にさまざまなボタンとテキストが表示されていることがわかります。

ドライバーが乗車ピックアップに向かう際の CardView のスクリーンショット。

最後に、旅行データが含まれている一覧を参照して、テスト旅行のデータの格納方法を確認します。

SharePoint リストの trip のスクリーンショット。

キャンパスシャトルACEは旅行の作成に適しています。 最後の 2 つの手順は、ドライバーが乗客をピックアップし、目的地に乗客を運転する途中にあるシナリオを実装することです。

乗客のピックアップに途中で機能を追加する

次に、ドライバーが乗客を迎えに行く途中にある場合のシナリオを実装しましょう。

  • 次のコードを 使用 して、 ./src/adaptiveCardExtensions/campusShuttle/quickView/template フォルダーに新しいファイル UpdateTripCard.jsonを追加します。

    {
      "schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "text": "${title}"
        }
      ],
      "actions": [
        {
          "id": "cancel",
          "type": "Action.Submit",
          "title": "Cancel Current Trip"
        },
        {
          "id": "pickup",
          "type": "Action.Submit",
          "title": "Pickup Passenger",
          "style": "positive"
        }
      ]
    }
    
  • 次のコードを使用して、./src/adaptiveCardExtensions/campusShuttle/quickView フォルダーに新しいファイル UpdateTrip.tsを追加して、UpdateTrip QuickView を実装します。

    import {
      IActionArguments,
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import {
      STATUS_HIRED,
      upsertListItem
    } from '../sp.service';
    
    export interface IUpdateTripData {
      title: string;
    }
    
    export class UpdateTrip extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      IUpdateTripData
    > {
      public get data(): IUpdateTripData {
        return {
          title: 'Update the existing trip'
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/UpdateTripCard.json');
      }
    
      public onAction(action: IActionArguments): void {
        if (action.type !== 'Submit') { return; }
    
        switch (action.id) {
          case 'cancel':
            // TODO QuickView cancelTrip
            break
          case 'pickup':
            // update current item status
            const trip = this.state.currentTrip;
            trip.Status = STATUS_HIRED;
    
            // save to list
            (async () => {
              await upsertListItem(this.context, this.properties.listId, trip);
            })();
    
            // update ACE
            this.setState({ currentTrip: trip });
    
            this.quickViewNavigator.close();
            break
          default:
            return;
        }
      }
    
    }
    

ドライバーが旅行をキャンセルするか、乗客を引き渡すことによって、旅行を削除したい場合は、プロジェクトに確認手順が必要です。 これを実装するには、両方のケースを動的に処理する単一の確認 QuickView を使用します。

  • 次のコードを 使用 して、 ./src/adaptiveCardExtensions/campusShuttle/quickView/template フォルダーに新しいファイル ConfirmationCard.jsonを追加します。

    {
      "schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "text": "${title}",
          "size": "Large"
        },
        {
          "type": "TextBlock",
          "text": "${description}"
        }
      ],
      "actions": [
        {
          "id": "confirm",
          "type": "Action.Submit",
          "title": "${title}",
          "style": "positive"
        }
      ]
    }
    
  • 確認 QuickView を実装するには、次のコードを使用して、新しいファイル ConfirmationQuickView.ts./src/adaptiveCardExtensions/campusShuttle/quickView フォルダーに追加します。

    import {
      IActionArguments,
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import {
      deleteListItem,
      STATUS_AVAILABLE
    } from '../sp.service';
    
    export interface IConfirmationQuickViewData {
      title: string;
      description: string;
    }
    
    export class ConfirmationQuickView extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      IConfirmationQuickViewData
    > {
      constructor(private confirmType: 'cancel' | 'complete') {
        super();
      }
    
      public get data(): IConfirmationQuickViewData {
        return {
          title: `${this.confirmType.substring(0,1).toUpperCase()}${this.confirmType.substring(1,this.confirmType.length)} Trip`,
          description: `Are you sure you want to ${this.confirmType} the trip?`
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/ConfirmationCard.json');
      }
    
      public onAction(action: IActionArguments): void {
        if (action.type === 'Submit' && action.id === 'confirm') {
          (async () => {
            // delete list item
            await deleteListItem(this.context, this.properties.listId, Number(this.state.currentTrip.Id));
          })();
    
          // update state to initial value
          this.setState({
            currentTrip: {
              Title: this.context.pageContext.user.loginName,
              Status: STATUS_AVAILABLE
            }
          });
    
          // close
          this.quickViewNavigator.close();
        }
      }
    }
    

これら 3 つの新しい QuickView を使用するには、それらを登録する必要があります。

  1. ./src/adaptiveCardExtensions/campusShuttle/quickView/index.ts ファイルを開き、新しい QuickView をエクスポートします。

    // .. existing export statements
    export * from './UpdateTrip';
    export * from './ConfirmationQuickView';
    
  2. ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts ファイルを開きます。

    1. 既存の import を更新して QuickView をインポートし、新しい QuickView を参照します。

      import {
        StartTrip,
        SetOrigin,
        SetDestination,
        SaveTrip,
        UpdateTrip,            // << add
        ConfirmationQuickView  // << add
      } from './quickView';
      
    2. CardView と QuickView の ID を宣言する定数を見つけ、新しい QuickView に次の ID を追加します。

      export const QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID: string = 'CampusShuttleCopilot_CancelTrip_QUICK_VIEW';
      export const QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID: string = 'CampusShuttleCopilot_CompleteTrip_QUICK_VIEW';
      export const QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID: string = 'CampusShuttleCopilot_UpdateTrip_QUICK_VIEW';
      

      最初の 2 つの定数が確認 QuickView を参照しない方法に注目してください。 これは、同じ QuickView の 2 つの実装を作成するためです。

    3. CampusShuttleAdaptiveCardExtension クラスの onInit() メソッド内で、StartTrip QuickView を登録した this.quickViewNavigator.register() ステートメントを既存の呼び出しの後に次のコードを追加します。

      this.quickViewNavigator.register(QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID, () => new ConfirmationQuickView('cancel'));
      this.quickViewNavigator.register(QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID, () => new ConfirmationQuickView('complete'));
      this.quickViewNavigator.register(QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID, () => new UpdateTrip());
      

最後の手順では、QuickView を既存の CardView と QuickView に接続します。

  1. ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts ファイルを見つけて開きます。

    1. CampusShuttleCopilotAdaptiveCardExtension モジュール内のプロパティ インターフェイスと状態インターフェイスを参照する既存のimport ステートメントを見つけます。 更新プログラムの 3 つの定数をインポートし、新しい QuickView を完了するように更新します。

      import {
        ICampusShuttleAdaptiveCardExtensionProps,
        ICampusShuttleAdaptiveCardExtensionState,
        QUICK_VIEW_START_TRIP_REGISTRY_ID,
        QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID,    // << add
        QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID   // << add
      } from '../CampusShuttleAdaptiveCardExtension';
      
    2. cardButton() アクセサー メソッドで、switch ステートメントを更新して、さらにボタンを追加します。

      1. case STATUS_ENROUTE return ステートメントに次のボタンを追加します。

        {
          title: 'Update Trip',
          action: {
            type: 'QuickView',
            parameters: { view: QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID }
          }
        }
        
      2. case STATUS_HIRED return ステートメントに次のボタンを追加します。

        {
          title: 'Complete Trip',
          action: {
            type: 'QuickView',
            parameters: { view: QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID }
          }
        }
        
  2. ./src/adaptiveCardExtensions/campusShuttle/quickView/UpdateTrip.ts ファイルを見つけて開きます。

    1. CampusShuttleCopilotAdaptiveCardExtension モジュール内のプロパティ インターフェイスと状態インターフェイスを参照する既存のimport ステートメントを見つけます。 更新プログラムの 3 つの定数をインポートし、新しい QuickView を完了するように更新します。

      import {
        ICampusShuttleAdaptiveCardExtensionProps,
        ICampusShuttleAdaptiveCardExtensionState,
        QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID    // << add
      } from '../CampusShuttleAdaptiveCardExtension';
      
  3. onAction() メソッドのコメント // TODO QuickView cancelTripを次に置き換えて、SetOrigin QuickView を実装します。

    this.quickViewNavigator.push(QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID);
    

テスト旅行管理エクスペリエンス

この時点で、ブラウザーで旅行管理エクスペリエンスをテストできます。

以前にローカル Web サーバーを停止した場合は、コンソールで次のコマンドを実行して再起動します。

gulp serve --nobrowser

SharePoint でホストされているワークベンチに移動して Campus Shuttle ACE を表示し、ツール バーの右上にある [プレビュー ] ボタンを選択します。

CardView に [ トリップの更新] ボタンが含まれていることに注目してください。

更新された CardView のスクリーンショット。

[ 乗車の更新 ] ボタンを選択すると、乗客をキャンセルまたはピックアップするためのオプションが 2 つあります。

UpdateTrip QuickView のスクリーンショット。

[現在の 旅行のキャンセル ] ボタンを選択すると、ACE の状態がリセットされ、SharePoint リストからドライバーのレコードが削除されます。 [ ピックアップ乗客 ] ボタンを選択すると、ACE 状態と SharePoint リスト アイテムの両方で乗車が更新され、旅行の状態が 途中 から採用済みに変更 されます

[ 乗車客 ] ボタンを選択します。 CardView コンテキストとボタンが変更され、乗車状態の変更が示されます。

ドライバーが乗客を目的地に連れて行くときの CardView のスクリーンショット。

最後に、[旅行の 完了 ] ボタンを選択して確認の QuickView を表示し、[ 旅行の完了 ] ボタンを選択して確認します。 これで旅行が完了します。

クイック ビューの確認のスクリーンショット。

この演習では、Viva Connectionsの geo 位置情報機能を使用する [プライマリ テキスト カード] オプションを使用して SPFx ACE を作成しました。

自分の知識をテストする

1.

開発者は、コンテキスト データを使用して CardViews と QuickView を動的にするにはどうすればよいですか?

2.

VivaConnections.SelectMedia アクションを使用する場合、開発者は選択したイメージを SharePoint ドキュメント ライブラリに保存する方法を教えてください。

3.

VivaLocation.ShowLocation アクションで場所を設定するには、開発者は GPS 座標を緯度と経度、または場所の番地として指定できます。