はじめての SharePoint のアダプティブ カード拡張機能を構築します

アダプティブ カード拡張機能 (ACE) は、新しいSharePoint Framework コンポーネントの種類であり、開発者は、Viva Connectionsのダッシュボードと SharePoint Pages に対して豊富でネイティブな拡張機能を構築できます。 アダプティブ カード拡張機能では、Microsoft のアダプティブ カード フレームワークを使用して宣言型 JSON スキーマを使った UI を生成するため、コンポーネントのビジネス ロジックに焦点を当てるだけでよく、あとは SharePoint Framework (SPFx) がコンポーネントの外観をよくし、すべてのプラットフォームで動作するようにしてくれます。

重要

このチュートリアルは、SPFx v1.13 がインストールされていることを前提としています。 SPFx v1.13 のインストールの詳細については、「SharePoint Framework v1.13 のリリース ノート」を参照してください。

アダプティブ カード拡張機能プロジェクトをスキャフォールディングする

プロジェクトの新しいプロジェクト ディレクトリを作成し、現在のフォルダーをそのディレクトリに変更します。

作成した新しいディレクトリから Yeoman の SharePoint ジェネレーターを実行して、新しいプロジェクトを作成します。

yo @microsoft/sharepoint

プロンプトが表示されたら、以下の値を入力します (以下で省略されたすべてのプロンプトに対して既定のオプションを選択します):

  • テナント管理者が、サイトで機能の展開を実行したり、アプリを追加したりすることなく、すぐにすべてのサイトでソリューションを展開できるようにしたいですか? はい
  • どの種類のクライアント側コンポーネントを作成しますか? アダプティブ カード エディター
  • どのテンプレートを使用しますか? プライマリ テキスト テンプレート
  • アダプティブ カード拡張機能の名前は何ですか? HelloWorld
  • アダプティブ カード拡張機能の説明は何ですか? Hello Worldの説明

この時点で、Yeoman は必須の依存関係をインストールし、ソリューション ファイルをスキャフォールディングします。 このプロセスには数分かかる場合があります。

プロジェクトのホストされたワークベンチの URL を更新する

gulp タスク serve を使用すると、既定ではブラウザーを起動し、プロジェクトで指定された、ホストされたワークベンチ URL を開きます。 新しいプロジェクトでのホストされたワークベンチの既定の URL は、無効な URL を参照します。

  • プロジェクト内の ./config/serve.json ファイルを見つけて開きます。

  • プロパティ initialPage を見つけます。

    {
      "$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
      "port": 4321,
      "https": true,
      "initialPage": "https://enter-your-SharePoint-site/_layouts/workbench.aspx"
    }
    
  • enter-your-SharePoint-site ドメインをテストに使用する SharePoint テナントとサイトの URL に変更します。 例: https://contoso.sharepoint.com/sites/devsite/_layouts/workbench.aspx

ヒント

gulp serve コマンドに nobrowser 引数を含めることで、ブラウザーを起動せずにローカル Web サーバーを起動することもできます。 たとえば、すべてのプロジェクトで serve.json ファイルを変更するのではなく、ブックマークを使用してホストされたワークベンチを起動します。

gulp serve --nobrowser

ワークベンチで ACE のサービスを提供する

コードを掘り下げる前に、スキャフォールディングされた出力を実行し、アダプティブ カード拡張機能がどのようなものになるかを確認します。

ACE を使用した内部開発ループは、SPFx Web パーツに似ています。 ローカルでサービスを提供し、ワークベンチでコードを実行できます。

gulp serve

ローカル Web サーバーが実行されたら、ホストされているワークベンチに移動します。 https://{tenant}.sharepoint.com/_layouts/15/workbench.aspx

Web パーツ ツールボックスを開き、ACE を選択します。

ツールボックスから ACE を選択します

カード ビューを確認します

ACE は 2 つの異なる方法でレンダリングできます。 ACE をレンダリングする最初の方法は、カード ビュー と呼ばれます。

ダッシュボードまたはページにレンダリングされる場合、ACE は常にこのビューで開始されます。

カード ビューでレンダリングされた ACE

クイック ビューを確認します

ACE をレンダリングするもうひとつの方法は、クイック ビュー と呼ばれます。 ACE を操作すると、ACE により、より大きな、カスタマイズされたエクスペリエンスを起動できます。

注:

編集 モードでは、ACE 操作が無効になっています。 ワークベンチ、またはページが ACE と対話するには、プレビュー または 読み取り モードでなければなりません。

ワークベンチを プレビュー モードに切り替えます。

ワークベンチをプレビュー モードに設定します

ACE の [クイック ビュー] ボタンを選択します。

ACE の [クイック ビュー] ボタンを選択します

スキャフォールディングされたコードを調べる

ベース クラスを検索します

プロジェクトで次のファイルを見つけて開きます。 ./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts

export default class HelloWorldAdaptiveCardExtension
  extends BaseAdaptiveCardExtension<IHelloWorldAdaptiveCardExtensionProps,IHelloWorldAdaptiveCardExtensionState> {
  // ...
}

すべての ACE は、BaseAdaptiveCardExtension クラスから拡張する必要があります。 必要に応じて、次の 2 つのジェネリックを実装できます。

  • TProperties: Web パーツと同様に、これはコンポーネントの永続化されたプロパティのセットです (プロパティ バッグ)。
  • TState: ACE に一意であり、必要に応じてレンダリング可能なデータのセットを定義できます。

ACE のレンダリング

protected renderCard(): string | undefined {
  return CARD_VIEW_REGISTRY_ID;
}

renderCard() メソッドは、登録済みのビューに文字列識別子を返す virtual です。詳細については、後で [登録の表示] で説明します。 このメソッドは、カード ビューの初期レンダリング中に呼び出されます。

renderCard() がオーバーライドされない場合は、既定のカード ビューがレンダリングされます。

renderCard() メソッドをコメント アウトし、何が起こるかを確認します。

/*
protected renderCard(): string | undefined {
  return CARD_VIEW_REGISTRY_ID;
}
*/

renderCard() メソッドをコメントした結果

元の状態に戻すには、renderCard() メソッドをコメント解除します。

既定のカード ビューでは、マニフェストから次のプロパティを使用してレンダリングされます:

  • アイコン: iconProperty
  • 役職: title
  • カード テキスト: description

注:

カード ビューとは異なり、既定のクイック ビューはありません。

ACE のビューの登録

ビューを使用するには、それぞれの ViewNavigator に登録する必要があります。 2 つの ViewNavigator が ACE で公開されています: cardNavigatorquickViewNavigator:

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

注:

使用する前にビューを登録する必要があります。 これは、クラスのコンストラクターまたは onInit() メソッド内で行うことができます。

カード ビュー

次のファイルを見つけて開きます: ./src/adaptiveCardExtensions/helloWorld/cardView/CardView.ts

カード ビューは、これらの基本クラスから拡張する必要があります。

  • BaseBasicCardView

    BaseBasicCardView

  • BaseImageCardView

    BaseImageCardView

  • BasePrimaryTextCardView

    BasePrimaryTextCardView

これらのビューはそれぞれ異なる方法でレンダリングされ、テンプレートに提供できるデータに対して様々な制約があります。

注:

アダプティブ カード テンプレートのカード ビューは固定されており、変更できません。

さらに、ビューと ACE の間で共有される properties オブジェクトと state オブジェクトのジェネリックが 2 つあります。

  • TProperties: ビューのプロパティ インターフェイス。ACE の永続化されたプロパティで使用されるインターフェイスと同じです (プロパティ バッグ)。
  • TState: ACE に一意であり、必要に応じてレンダリング可能なデータのセットを定義できます。

注:

SPFx は ACE の状態に対する変更を各ビューに自動的に伝達します。

data getter は、カード ビューで実装する必要がある唯一のメソッドです。 戻り値の型は、ビューの親クラスに一意です。

cardButtons プロパティは、カードに表示されるボタンの数と、クリック時に実行するアクションを決定します。

cardButtons が実装されていない場合、カードにボタンは表示されません。

注:

初期のカード ビューは ACE の renderCard() メソッドで指定されますが、初期のクイック ビューはボタンのアクション parametersの一部として指定されます。 これにより、2 つのボタンで異なるビューを開くことができるのです。

cardButtons() メソッドによって返される配列に別のオブジェクトを追加して、2 番目のボタンを追加します。

public get cardButtons(): [ICardButton] | [ICardButton, ICardButton] | undefined {
  return [
    {
      title: strings.QuickViewButton,
      action: {
        type: 'QuickView',
        parameters: {
          view: QUICK_VIEW_REGISTRY_ID
        }
      }
    },
    {
      title: 'Bing',
      action: {
        type: 'ExternalLink',
        parameters: {
          target: 'https://www.bing.com'
        }
      }
    }
  ];
}

最初は、カードに変更はありません。 これは、BasePrimaryTextCardViewMedium カード サイズにはボタンが 1 つだけ表示されるためです。 SPFx はタプルの最初の要素を選択します。

  1. [プロパティ] ウィンドウに移動し、[Large] を選択して、カードのサイズを変更します。

    カードのサイズの選択

    レンダリングされた大きなサイズの ACE カード

  2. ここで、[Bing] ボタンを選択すると、Bing が新しいブラウザー タブを開きます。

onCardSelection() メソッドは、カードをクリックしたときの処理を決定します。 onCardSelection() メソッドが実装されていない場合、カードをクリックしても何も起こりません。

  1. カードの選択を変更し、onCardSelection() メソッドを変更して クイック ビューを開きます。

    public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined {
      return {
        type: 'QuickView',
        parameters: {
          view: QUICK_VIEW_REGISTRY_ID
        }
      };
    }
    
  2. これで、カードを選択すると、クイック ビューが開くようになりました。

ACE のクイック ビュー

次のファイルを見つけて開きます: ./src/adaptiveCardExtensions/helloWorld/quickView/QuickView.ts

クイック ビューでは、BaseAdaptiveCardView 基本クラスを拡張する必要があります。 定義できるオプションのジェネリックは 3 つあります:

  • TData: data() getter メソッドから返される型。
  • TProperties: カード ビューと同様に、これは ACE の永続化されたプロパティで使用されるインターフェイスと同じです。 (プロパティ バッグ) 。
  • TState カード ビューと同様に、これはビューがレンダリングする必要があるステートフル データのセットです。 TState は、ACE の状態インターフェイスとプロパティを共有する必要があります。

クイック ビューでは、カード ビューよりもアダプティブ カード テンプレート スキーマをより細かく制御できます。 template() getter は、有効なアダプティブ カード テンプレート JSON を返す必要があります。 SPFx ACE では、アダプティブ カード テンプレートがサポートされています。 data getter から返されるオブジェクトのプロパティは、バインドされたテンプレート スロットに自動的にマップされます。

たとえば、 ${description}this.properties.descriptionにバインドされます。

// QuickView.ts
public get data(): IQuickViewData {
  return {
    // ...
    description: this.properties.description
  };
}
// QuickViewTemplate.json.ts
{
  "type": "TextBlock",
  "text": "${description}",
  "wrap": true
}

注:

${} の角かっこを使用する、アダプティブ カード バインド構文を使用する必要があります。

これを変更しましょう。

  1. クイック ビュー データから description プロパティを削除し、2 つのボタンを追加します。

  2. 次のコードに示すように、IQuickViewData インターフェイスを更新します。

    export interface IQuickViewData {
      title: string;
      subTitle: string;
    }
    
  3. 次のコードに示すように、data() メソッドを更新します。

    public get data(): IQuickViewData {
      return {
        subTitle: this.state.subTitle,
        title: strings.Title
      };
    }
    
  4. 次のファイルを見つけて開きます: ./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts

  5. 次のように、IHelloWorldAdaptiveCardExtensionState インターフェイスと onInit() メソッドを更新します。

    export interface IHelloWorldAdaptiveCardExtensionState {
      subTitle: string;
    }
    
    ..
    
    public onInit(): Promise<void> {
      this.state = {
        subTitle: 'No button clicked'
      };
      // ...
    }
    

次に、カード ビューから this.properties.description への参照を削除します。

  1. 次のファイルを見つけて開きます: ./src/adaptiveCardExtensions/helloWorld/cardView/CardView.ts

  2. 返されたオブジェクトの description プロパティを削除します。

    public get data(): IPrimaryTextCardParameters {
      return {
        primaryText: strings.PrimaryText
      };
    }
    

その template() getter では、生成した ACE のクイック ビューにより JSON ファイルからのオブジェクトが返されます。 次に、そのテンプレートを変更してみましょう。

  1. 次のファイルを見つけて開きます: ./src/adaptiveCardExtensions/helloWorld/quickView/template/QuickViewTemplate.json

  2. ファイルのコンテンツを次の JSON で置き換えます:

    {
      "schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.2",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "text": "${title}"
        },
        {
          "type": "TextBlock",
          "text": "${subTitle}",
          "wrap": true
        },
        {
          "type": "ActionSet",
          "actions": [
            {
              "type": "Action.Submit",
              "title": "Button One",
              "style": "positive",
              "data": {
                "id": "button1",
                "message": "Clicked Button One"
              }
            },
            {
              "type": "Action.Submit",
              "title": "Button Two",
              "data": {
                "id": "button2",
                "message": "Clicked Button Two"
              }
            }
          ]
        }
      ]
    }
    

ブラウザーでホストされているワークベンチを更新して、変更をテストします。 gulp serve がまだ実行されている場合は、プロジェクトに適用した変更を受け取る必要があります。

更新された ACE クイック ビュー

ヒント

アダプティブ カードの詳細については、https://adaptivecards.io を参照してください。 このサイトには、アダプティブ カードの作成時にレンダリングと構造をプレビューできるアダプティブ カード デザイナーも含まれています。

この時点で、クイック ビュー カードに 2 つの新しいボタンが含まれるように ACE を変更しました。 次の手順では、これらのボタンが選択されたときに何が起こるかを実装します。 これは、アクション ハンドラーを使用して行われます。

アクション ハンドラー

アクションは、それが定義されているビューによって処理されます。

クイック ビューには 2 つのボタンがありますが、現在、ビューは 提出アクションを処理していません。 onAction() メソッドは、アダプティブ カード アクションが実行されるたびに呼び出されます。たとえば、Action.Submit アクションが開始された場合などです。

次のコードに示すように、QuickView.ts ファイルを見つけて開き、onAction() をオーバーライドして 2 つのボタンの選択を処理します。

import { ISPFxAdaptiveCard, BaseAdaptiveCardView, IActionArguments } from '@microsoft/sp-adaptive-card-extension-base';

..

public onAction(action: IActionArguments): void {
  if (action.type === 'Submit') {
    const { id, message } = action.data;
    switch (id) {
      case 'button1':
      case 'button2':
        this.setState({
          subTitle: message
        });
        break;
    }
  }
}

ブラウザーでホストされているワークベンチを更新して、変更をテストします。 gulp serve がまだ実行されている場合は、プロジェクトに適用した変更を受け取る必要があります。

いずれかのボタンを選択すると、状態の subTitledata.message 値に設定され、再レンダリングが発生します (詳しくは後述します)。 クイック ビューのアダプティブ カードでは、テンプレートが subTitle にバインドされるため、このメッセージが表示されるようになりました。

プロパティ ウィンドウ

Web パーツと同様に、ACE は、適切なアクセス許可を持つユーザーによって設定される構成可能なプロパティを持つことができます。 これにより、ACE の各実装をカスタマイズできます。 これには、プロパティ ウィンドウを使用します。

ACE は、Web パーツと同様に構成できます。 API シグネチャは、HelloWorldAdaptiveCardExtension.ts ファイルにある次のメソッドと同じです。

  • getPropertyPaneConfiguration()
  • onPropertyPaneFieldChanged()

ACE の既定のスキャフォールディングでは、コンポーネントが 編集 モードでない場合にバンドル サイズを最小化することを目的とした新しい API が使用されます。 loadPropertyPaneResources() メソッドは、Webpack のチャンク機能を利用して、プロパティ ウィンドウ固有のコードを独自の JS ファイルに分離します。そうすることで、これをオンデマンドで読み込むことができます。

プロパティ ウィンドウの構成を返すだけでなく、 HelloWorldPropertyPane クラスを使用して、すべての 編集 モード ロジックをカプセル化します。

プロパティ

カード サイズ フィールド以外に、スキャフォールディングされた ACE には、IHelloWorldAdaptiveCardExtension インターフェイスで定義されているメソッド&でgetPropertyPaneConfiguration()定義されている 3 つの (3) 構成可能なフィールドがあります。

  • title
  • iconProperty
  • description

カード ビューは、すべてのカード サイズで自動的に動作するように設計されています。 既定のカード サイズを指定する以外に、ACE はこのプロパティを制御できません。

ACE ファイルで定義されている title および iconProperty プロパティ (例: HelloWorldAdaptiveCardExtension.ts) は、 カードのタイトルとアイコンを構成するために、ACE の title() および iconProperty() getter で使用されます。

title 値は、プロパティ ウィンドウのタイトルとカードに表示されるタイトルで使用されます。

public get title(): string {
  return this.properties.title;
}

iconProperty 値は、カード ビューで使用されるアイコンの URL になります。

protected get iconProperty(): string {
  return this.properties.iconProperty || require('./assets/sharepointlogo.png');
}

状態

state プロパティは、setState() メソッドを呼び出す前に初期化する必要があり、1 回だけ初期化することができます。

public onInit(): Promise<void> {
  this.state = {
    subTitle: 'No button clicked'
  };
  // ...
}

properties とは異なり、state は現在のセッションを過ぎても保持されず、一過性のビュー状態にのみ使用する必要があります。

注:

スキャフォールディングされた ACE は、state オブジェクトの description プロパティを保持します。 ACE とそのすべてのビューは、単に properties に格納されている description を参照できるため、これは旧式です。

再レンダリング

再レンダリングは、PropertyPane でプロパティが更新されたとき、または setState() が呼び出された場合に発生します。

プロパティ ウィンドウの 説明フィールド値を更新すると、カードの説明が更新されます。 これを行う方法を見てみましょう。

  1. 次のファイルを見つけて開きます: ./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts

  2. 簡単な例として、onPropertyPaneFieldChanged イベント中に description が更新されたときに subTitle 値を更新します。 ACE の HelloWorldAdaptiveCardExtension クラスに次のコードを追加します:

    protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
      if (propertyPath === 'description') {
        this.setState({
          subTitle: newValue
        });
      }
    }
    

1 つのPartial<TState> オブジェクトを setState() メソッドに渡すと、すべてのビューが新しい値で更新されます。 プロパティ ウィンドウで 説明フィールド を更新すると、クイック ビューに表示される subTitle が更新されます。

値が渡されない場合や同一の値が渡された場合でも、再レンダリングが行われます。

setState() メソッドは、プロパティ ウィンドウに限定されるだけではありません。 これは、新しいデータの受信に応じて、または何らかのユーザー操作の結果として使用できます。

結論

このチュートリアルの修了後、以下のことが理解できるようになります:

  • アダプティブ カード拡張機能のスキャフォールディング
  • ビューの登録
  • カード ビューとクイック ビューの変更
  • 基本的なアクション処理
  • プロパティ ウィンドウの変更
  • プロパティ ウィンドウの読み込みの延期
  • state の使用法
  • propertiesstate の差