はじめに
Power AutomateでPower Apps CardsをTeamsに送ることができるようになったそうです。
powerapps.microsoft.com
なので早速試してみましたので、今回はそのまとめです。
そもそもPower Apps Cardsってなに?という方は前にPower Apps Cardsについてまとめた記事があるのでこちらをご覧ください。
koruneko.hatenablog.com
公式のlearnはこちら
learn.microsoft.com
試してみた
使用するアクション
Power AutomateでPower Apps CardsをTeamsに送るには、まずは"Create card instance (プレビュー)"でPower Apps Cardsのインスタンスを作成する必要があります。
このアクションは"Cards for Power Apps"コネクタにあります。
このアクションで作成されたPower Apps Cardsのインスタンス情報を用いてTeamsコネクタの"Post card in a chat or channel"アクションを利用してTeamsに送ります。
Power Apps Cardsの作成
今回作成したPower Apps Cardsは以下のような感じ。
これは以下のようなJSONで構成されています。
{
"name": "TeamsでCardの送信テスト",
"description": null,
"author": "korune コルネ",
"screens": {
"main": {
"template": {
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "extraLarge",
"weight": "bolder",
"text": "Power Apps Card",
"id": "textLabel1",
"color": "accent"
},
{
"type": "TextBlock",
"text": "Power Apps カード(プレビュー) は、エンタープライズ データとワークフロー、と他のアプリケーションがコンテンツとして使用できるインタラクティブで軽量な UI 要素を備えたマイクロアプリです。 これらは Power Apps エコシステムの一環であることから、カードは Power Fx を通じてビジネス ロジックとPower Platform コネクタを通じてビジネス データと統合できます。 カードを使用すると、コーディングや IT の専門知識がなくても、リッチで実用的なアプリをすばやく作成および共有できます。",
"wrap": true,
"id": "textLabel2",
"size": "small",
"weight": "lighter",
"isSubtle": true
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"id": "列1",
"width": "auto",
"items": [
{
"type": "TextBlock",
"id": "テキストラベル1",
"wrap": true,
"text": "あなたが最後にカードを更新した時刻は"
}
]
},
{
"type": "Column",
"id": "列2",
"width": "auto",
"items": [
{
"type": "TextBlock",
"id": "テキストラベル2",
"wrap": true,
"text": "=Text(DateAdd(NowTime, 9, TimeUnit.Hours), \"yyyy/mm/dd hh:mm:ss\")"
}
]
},
{
"type": "Column",
"id": "列3",
"width": "auto",
"items": [
{
"type": "TextBlock",
"id": "テキストラベル3",
"wrap": true,
"text": "です。"
}
]
}
],
"separator": true
},
{
"type": "FactSet",
"id": "ファクトセット1",
"facts": [
{
"type": "Fact",
"title": "Title",
"value": "=myTask.title"
},
{
"type": "Fact",
"title": "User",
"value": "=myTask.user"
},
{
"type": "Fact",
"title": "start",
"value": "=myTask.startDateTime"
},
{
"type": "Fact",
"title": "due",
"value": "=myTask.dueDateTime"
},
{
"type": "Fact",
"title": "Complete",
"value": "=myTask.percentComplete"
}
]
},
{
"type": "TextBlock",
"id": "テキストラベル5",
"wrap": true,
"text": "このメッセージを確認したらボタンを押してください。",
"color": "attention"
},
{
"type": "Input.Text",
"id": "テキスト入力1",
"text": "=$\"\"",
"placeholder": "コメントを入力"
},
{
"type": "ColumnSet",
"id": "列セット1",
"columns": [
{
"type": "Column",
"id": "列8",
"width": "auto",
"items": [
{
"type": "TextBlock",
"id": "テキストラベル11",
"wrap": true,
"text": "現在の回答数"
}
]
},
{
"type": "Column",
"id": "列9",
"width": "auto",
"items": [
{
"type": "TextBlock",
"id": "テキストラベル10",
"wrap": true,
"text": "=CountIf(myUserTable, !IsBlank(user))"
}
]
}
]
}
],
"actions": [
{
"type": "Action.Execute",
"id": "ボタン1",
"title": "コメントを追加/更新",
"associatedInputs": "auto",
"verb": "onSelect_Button1"
},
{
"type": "Action.Execute",
"id": "ボタン2",
"title": "コメント済みユーザー一覧を確認",
"associatedInputs": "auto",
"verb": "onSelect_Button2"
}
],
"$schema": "http://adaptivecards.io/schemas/1.4.0/adaptive-card.json",
"version": "1.4"
},
"verbs": {
"onSelect_Button1": "If(\r\n IsBlank(LookUp(myUserTable, user = User().name)),\r\n Collect(\r\n myUserTable, \r\n {\r\n user: User().name,\r\n comment: テキスト入力1\r\n }\r\n ),\r\n Patch(\r\n myUserTable,\r\n LookUp(myUserTable, user = User().name),\r\n {\r\n user: User().name,\r\n comment: テキスト入力1\r\n }\r\n )\r\n)",
"submit": "echo",
"onSelect_Button2": "Navigate(watchedUser)"
}
},
"watchedUser": {
"template": {
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "extraLarge",
"weight": "bolder",
"text": "確認済みユーザー",
"id": "textLabel1"
},
{
"type": "TextBlock",
"text": "=Concat(\r\n Filter(myUserTable, !IsBlank(user)),\r\n ThisRecord.user & \": \" & ThisRecord.comment & \", \"\r\n)",
"wrap": true,
"id": "textLabel2",
"separator": true
}
],
"actions": [
{
"type": "Action.Execute",
"id": "ボタン3",
"title": "戻る",
"associatedInputs": "auto",
"verb": "onSelect_Button3"
}
],
"$schema": "http://adaptivecards.io/schemas/1.4.0/adaptive-card.json",
"version": "1.4"
},
"verbs": {
"onSelect_Button3": "Back()"
}
}
},
"sampleData": {
"main": {},
"watchedUser": {}
},
"connections": {},
"variables": {
"NowTime": {
"type": "object",
"title": "",
"description": "",
"default": "=Now()",
"x-ms-cardapp": {
"scope": "session"
}
},
"myUserTable": {
"type": "array",
"title": "",
"description": "",
"default": [
{
"user": "",
"comment": ""
}
],
"x-ms-cardapp": {
"scope": "shared"
}
},
"myTask": {
"type": "object",
"title": "",
"description": "",
"default": {
"title": "Title",
"startDateTime": "2000/1/1",
"dueDateTime": "2000/12/31",
"user": "Sample User",
"percentComplete": 0
},
"x-ms-cardapp": {
"scope": "session",
"input": "required"
}
}
},
"flows": {}
}
細かいカードの説明は今回省いて、簡単な説明だけ行います。
まず画面ですが、2画面作成してあります。
Adaptive Cardsと何か差別化できないかなーと色々考えて作成しています。(厳密にはこれもAdaptive Cardsなのですが)。
変数は3つ用意しました。
変数名 |
型 |
用途 |
NowTime |
Record |
現在時刻を設定するための変数 正直変数にしなくてもよかった(後述) |
myUserTable |
Table |
コメントを追加したユーザーを保存するテーブル |
myTask |
Record |
Power Automateから値を受けとるための変数 |
"記録"は"Record"です。
変な日本語訳しないでくれ。マジで。
説明の文章とかならともかくこういうものは英語で記載してくれたほうがわかりやすいと私は思うんですけどどうなんですかね?
テキストラベルに文字列と変数の値を同時に表示させることは2023/03/20時点ではできない?のでわざわざ文字列描画用のラベル変数描画用のラベルで分けています。
"コメントを追加/更新"を選択すると、テキスト入力で入力したコメント + 押したユーザーのユーザー名をmyUserTable
に設定しています。
既に登録済みの場合は、追加ではなく更新するようにしています。
この際、Power Apps CardsではUpdate関数やUpdateIf関数は利用できないのでPatch関数で更新をしています。
画面遷移は皆さんお馴染みのNavigate関数で行っています。
ただし、キャンバスアプリのように第二引数以降(アニメーションや変数渡し)は利用できないので注意。
テーブルの文字列表示にはConcat関数で表示させています。
Power Apps Cardsにはギャラリーなんて高級なものはないのでね...
この際にChar(10)
とかで改行させたかったのですが何故か動かない...
なぜ...?
ちなみにこの状態で再生を行ってもエラーが表示されて再生が行えません。
Full error:
myTask.title - Error 6-12: Invalid use of '.'
myTask.user - Error 6-11: Invalid use of '.'
myTask.startDateTime - Error 6-20: Invalid use of '.'
myTask.dueDateTime - Error 6-18: Invalid use of '.'
myTask.percentComplete - Error 6-22: Invalid use of '.'
こんな感じで、myTask
に設定した値を参照しようとするとエラーがでるんですよね。
なんでですか。
この状態でもPower AutomateでTeamsに送る分には(多分)支障ないのでいったん無視しています。
フローの作成
フローはこんな感じ
"ユーザー プロフィールの取得 (V2)"アクションまでは特に何の変哲もないフローですのでスキップします。
"Create card instance (プレビュー)"アクションでは、"Card"で作成したPower Apps Cardsを選択します。
選択したカードによって、設定するパラメータが異なってきます。
例えば先ほど作成したカードであれば、"myTask"で作成した変数は値をカスタマイズできるようにしていました。
このようにして作成した変数は上記のような形でフローから値を渡すことができます。
なにも設定されていないカードの場合は"Body"となるようです。
上記でPower Apps Cardsのインスタンスを作成した後、"Post card in a chat or channel"アクションでTeamsへメッセージを送ります。
"Post As"では"Power Apps"を選び、"Card"では先ほど作成したカードを選択しましょう。
なおこのアクションでは現在
の2種類にしか送ることができない(個人へは送れない)ようです。
Adaptive Cardとなにが違う?
さて、Power Apps Cardsとよく似たものでAdaptive Cardsがありますね。
Adaptive Cardsではできず、Power Apps Cardsではできることはなんなのでしょうか?
ざっと使ってみた感じ以下のようなことがあるかと思っています。
- Power Fxを利用可能
- Dataverseをコネクタとして接続可能
- 画面を分けることができる
- 変数の値を異なるユーザー間で共有できる
Dataverseを利用しているユーザーは2つ目の利点が大きいかもですね。
Dateverseの値をカードにリアルタイムに表示できるので。(試していない)
また、試してみておーっと思ったのですが、なんと変数の値をユーザー間で共有できるんですよね。
ユーザーA
ユーザーB
なので、このカードのように見た人とその人のコメントをカードに表示させて共有することができます。
(返信でいいのでは?というのは無しでお願いします。)
変数の値は送られたメッセージの右上の三点リーダーから"カードの更新"を選択した場合に更新されます。
この操作があるので、更新用ボタンを用意する必要もなく、また現在時間をわざわざ変数に入れなくてよかったんですよね。
おわりに
このフローのアクションを利用することで、Power Apps CardsをTeamsに送るときにリンクまで一緒に表示されなくなったのが個人的に大きいですね。
手動で送信
フローで送信
このリンク邪魔でしたよね?
3/20週からPower Apps Cardsでの変数と作成が容易になるように更新が入るようですね。
Improved authoring experience
We’ve received amazing feedback during the past few months of public preview and have made major updates to how cards for Power Apps are designed based on what we’ve heard.
With a no/low code editing pane, variables are now easier to create and manage. Rolling out the week of March 20th.
正直その他デザインももっと更新して欲しいというか、変な日本語訳やめてほしいのですが。。。
もし面白そうな使いかたありましたら教えてくださいー