ささみ学習帳 - sasami's study book

ささみ学習帳

Microsoft365 や Power Platform について学んだこと・アイデアのメモ

チャネルのピン留めされたメッセージをタブ表示する PowerApps アプリ (PowerApps for Teams)

 

はじめに

Teams チャネルのメッセージのピン留め機能使っていますか?チャットの場合は画面上部に固定表示される非常に分かりやすい機能ですが、チャネルの場合はピン留めされたメッセージを確認する為には情報ペインを開くひと手間が必要でその存在を知らない方も少なくないのではと思います。

今回は以前作成したPower Automateフローを応用してチャネルのタブとしてピン留めメッセージを表示するPower Appsアプリを作ってみました。

以前の記事はこちらです。

sasami-axis.hatenablog.com

 

Teams の新しいチャネルエクスペリエンスでは情報ペインが既定でOnに

Teams のチャネルが2023年7月下旬から展開予定の新しいチャネルエクスペリエンスでは、情報ペインが既定で表示されるように変わるようです。情報ペインが表示されていればピン留めメッセージへのアクセスも容易になります。このアプリは必要なくなってしましましたが記録として残しておきます。

 

 

【重要】非公開のAPIを利用しており一切のサポートはありません

このアプリのPowerAutomateフローでは文書化されていない Teams ネイティブな? API を使用しています。本来使われる想定がない形で機能を使用していますのである日突然使えなくなってしまう可能性もあります。マイクロソフト社のサポート対象外の使い方になりますので、運用環境では使用しない方が良いかと思います

 

事前準備

今回のアプリはPowerApps for Teamsで作成しました。

Teams に PowerApps アプリを追加します

アプリはチームに作成します。今回作成するチームにアプリを作成したことが無い場合は、下記の操作を行い環境を作成します。

Teams のウィンドウ左側のアプリバーからPower Appsにアクセスします。

「今すぐ始める」をクリック

アプリを配置するチームを選択し「作成」します。

初めてアプリをチームに作成する場合はしばらく待ちます。

 

Power Automate クラウドフローを作成する

ピン留めメッセージの情報を取得するフローを作成します。

PowerAutomateにアクセスし、右上の環境をクリックしアプリを作成するチーム名の環境を選択してからフローを作成します。

PowerApps内からフローを作成する事もできますが、こちらの方がおすすめです。

「listPinnedMessagesOnChannel_V3」フロー全体

 

フロー解説

1.PowerAppsから2つのパラメーターを渡しますので、既定で追加されているPowerAppsトリガーを削除し、PowerApps(V2)トリガーを追加します。

  • generalChannelId
    • 一般チャネルのId
  • targetChannelId
    • ピン留めの情報を取得するチャネルId

 

2.SharePointコネクタ-「SharePointにHTTP要求を送信します」アクションでピン留め情報を取得します。

  • サイトのアドレス:
  • 方法:
    • GET
  • URI
    • /api/csa/amer/api/v1/teams/{一般チャネルのchannel id}/channels/{ピン留めの情報を取得したいchannel id}/pins
  • ヘッダー:
    • Content-Type:application/json

このような形で取得できるはずです。

 

3.HTTP要求の結果をjson解析する際のスキーマ定義はこちらです。

{
    "type": "object",
    "properties": {
        "messages": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "messageType": {
                        "type": "string"
                    },
                    "content": {
                        "type": "string"
                    },
                    "clientMessageId": {
                        "type": "string"
                    },
                    "imDisplayName": {
                        "type": "string"
                    },
                    "properties": {
                        "type": "object",
                        "properties": {
                            "importance": {
                                "type": "string"
                            },
                            "languageStamp": {
                                "type": "string"
                            },
                            "pinned": {
                                "type": "string"
                            },
                            "edittime": {
                                "type": "integer"
                            },
                            "ams_references": {
                                "type": [
                                    "array",
                                    "null"
                                ]
                            }
                        }
                    },
                    "id": {
                        "type": "string"
                    },
                    "type": {
                        "type": "string"
                    },
                    "composeTime": {
                        "type": "string"
                    },
                    "originalArrivalTime": {
                        "type": "string"
                    },
                    "containerId": {
                        "type": "string"
                    },
                    "parentMessageId": {
                        "type": "string"
                    },
                    "from": {
                        "type": "string"
                    },
                    "sequenceId": {
                        "type": "integer"
                    },
                    "version": {
                        "type": "integer"
                    },
                    "threadType": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "isEscalationToNewPerson": {
                        "type": "boolean"
                    },
                    "contentType": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "fromTenantId": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "amsReferences": {
                        "type": [
                            "array",
                            "null"
                        ]
                    }
                },
                "required": [
                    "messageType",
                    "content",
                    "clientMessageId",
                    "imDisplayName",
                    "properties",
                    "id",
                    "type",
                    "composeTime",
                    "originalArrivalTime",
                    "containerId",
                    "parentMessageId",
                    "from",
                    "sequenceId",
                    "version",
                    "threadType",
                    "isEscalationToNewPerson"
                ]
            }
        }
    }
}

 

4.PowerAppsで扱いやすいように データ操作-選択アクションで、必要な項目のみを選択します。

 

アイテム名 説明
imDIsplayName メッセージ投稿者表示名
content メッセージ本文
subject メッセージ件名
title メッセージアナウンスタイトル
webUrl

メッセージリンクURL

https://teams.microsoft.com/l/message/@{triggerBody()['text_2']}/@{item()?['id']}?parentMessageId=@{item()?['parentMessageId']}
originalArrivalTime

メッセージ投稿日時

convertFromUtc(
    item()?['originalArrivalTime'],
    'Tokyo Standard Time',
    'yyyy/MM/dd HH:mm:ss'
)
from メッセージ投稿者ユーザーId
pinned ピン留めしたユーザーIdとピン留めした日時のjson

 

5.選択アクションの出力をPowerAppsに返します。

[
  {
    "imDisplayName": "アライ クマ",
    "content": "<div>\r\n<div itemprop=\"copy-paste-block\">\n\r\n<ol style=\"font-size:16px\">\r\n\n\t\r\n<li>こんにちは!お&#26172;ご飯は何を食べましたか?</li>\n</ol>\r\n\n</div>\n</div>",
    "subject": null,
    "title": null,
    "webUrl": "https://teams.microsoft.com/l/message/19:216740c0e6ca410a9d195953f8c37bba@thread.tacv2/1684497743914?parentMessageId=1684497743914",
    "originalArrivalTime": "2023/05/19 21:02:23",
    "from": "8:orgid:554f5e22-01b6-4a45-94bf-83044398ea99",
    "pinned": "{\"creatorId\":\"8:orgid:448060bd-fe71-424f-b70b-3456084c7ffd\",\"pinnedTime\":1684752709594}"
  },
  
【中略】
{ "imDisplayName": "ジャイアント パンダ", "content": "<p>猫を吸います!!!</p>", "subject": null, "title": null, "webUrl": "https://teams.microsoft.com/l/message/19:216740c0e6ca410a9d195953f8c37bba@thread.tacv2/1689250255589?parentMessageId=1684498142076", "originalArrivalTime": "2023/07/13 21:10:55", "from": "8:orgid:5e41bcfc-97b9-40ec-9f2c-8bef94b140d7", "pinned": "{\"creatorId\":\"8:orgid:479e2162-2151-4005-88c4-2029412d46b2\",\"pinnedTime\":1689291239743}" } ]

 

以上でフローの作成は完了です。

 

Power Apps for Teamsでアプリを作成する

アプリを作成する

Teams のウィンドウ左側のアプリバーからPower Appsにアクセスします。

ビルド→指定したチーム→新規→アプリ

 

データ接続の作成

「Microsoft Teams」を追加

「データの追加」→「データソースの選択」で検索欄で「Teams」と検索すると表示される「Microsoft Teams」コネクタを選択します。

 

「Office 365 ユーザー」を追加

同様に「Office 365 ユーザー」も追加します。

 

PowerAutomate フローを追加

フローの追加から上の手順で作成した「listPinnedMessagesOnChannel_V3」を追加します。

 

画面の構成

下図のような形で画面を構成します。

 



 

Screen1

OnVisible

Screen1が表示されたときに下記を実行するよう構成します。

OnVisibleをクリックし入力バーに下記のコードを入力します。

UpdateContext({
    channelId:Teams.ThisChannel.Id,
    channelIdGeneral:Teams.ThisTeam.Id
});

ClearCollect(colJson,
    listPinnedMessagesOnChannel_V3a.Run(channelIdGeneral,channelId)
);
ClearCollect(colMessages, ForAll( Table(ParseJSON(First(colJson).json)),{ imDIsplayName: Text(ThisRecord.Value.imDisplayName), context: PlainText(Text(ThisRecord.Value.content)), subject: Text(ThisRecord.Value.subject), title: Text(ThisRecord.Value.title), webUrl: Text(ThisRecord.Value.webUrl), teamsUrl: Text(ThisRecord.Value.teamsUrl), originalArrivalTime: Text(ThisRecord.Value.originalArrivalTime),
           from: Text(ThisRecord.Value.from),
            pinnedTime: Text(ParseJSON(Text(ThisRecord.Value.pinned)).pinnedTime)
        } ) );
  • Teams統合オブジェクトから必要な情報を取得
    Teams統合オブジェクトからチームId, 一般チャネルのチャネルId, ピン留めを取得するチャネルIdを取得します。
  • 取得した値をPowerAutomate フローに引き渡して実行
    Power Automateフローを実行し返されたJSONをコレクションcolJSONに格納します。
  • JSONをパースしてコレクションに格納
    colJSONの値をParseJSON関数でパースしてコレクションcolMessagesに格納します。この時、pinnedの値はJSONになっていますので、さらにparseJSON関数でパースしてpinnedTimeのみ取り出しています。

※Teams統合オブジェクトを参照しているとPowerApps for Teams内でアプリをプレビュー実行した場合には値を取得できません。その為上記のようにコレクションの中を確認することができません。上記はTeams統合オブジェクトを使用しないプロトタイプ版アプリで取得した際のコレクションです。

 

IconRefresh

OnSelect

 

Screen1 OnVisibleと同じ処理をコピペします。

 

LabelPinnedCount

Text

Itemsを選択し入力バーに下記のコードを入力します。

ピン留めメッセージの件数を表示します

CountRows(colMessages) & " 件のピン留めメッセージ"

 

Gallery1

Items

Itemsを選択し入力バーに下記のコードを入力します。colMessages を ピン留め日付の降順でソートしてます。

SortByColumns(colMessages,"pinnedTime",SortOrder.Descending)
OnSelect

OnSelectを選択し入力バーに下記のコードを入力します。

Launch(
    If(Param("hostClientType") = "desktop",
        Substitute(ThisItem.webUrl,"https://","msteams://"),
        ThisItem.webUrl
    )
)

Launch関数でURLを開きます。Param("hostClientType")で、現在実行中のクライアントタイプが取得できます(desktop, Web iOS, Android ...) Teamsデスクトップアプリで起動している場合のみ「msteams://teams.micro...」を起動し、その他では「http://teams.microsoft...」を起動します。こうする事で、Teamsデスクトップアプリ内でダイレクトにメッセージを開くことができます。

 

Subtitle1

Text

Itemsを選択し入力バーに下記のコードを入力します。

メッセージ投稿者とメッセージ投稿日時を表示します

ThisItem.imDIsplayName & " " & ThisItem.originalArrivalTime

 

Title1

Text

Textを選択し入力バーに下記のコードを入力します。

アナウンスタイトル, 件名, 本文を表示します

ThisItem.title & " " & ThisItem.subject & " " & ThisItem.content

 

ImageProfile

Image

Imageを選択し入力バーに下記のコードを入力します。

If(Len(ThisItem.from)>0,
    Office365ユーザー.UserPhotoV2(
        Substitute(
            ThisItem.from,
            "8:orgid:",
            ""
        )
    ),
    ""
)

PowerAutomateフローが返したfrom(ユーザーid)でユーザーのプロファイル画像を取得しています。fromの値の"8:orgid:"は、Office365ユーザー.UserPhotoV2のパラメーターには不要な為取り除いています。

"8:orgid:35975ed9-608b-408a-a362-19c1f3e1e844"

 

RadiusTopLeft, RadiusTopRight, RadiusBottomLeft, RadiusBottomRight

4つの値を24と設定することで、ユーザープロファイル画像を丸く表示します。

※Height ,Widhともに48で設定しています。

 

 

その他の位置調整やデザインなどはお好みで調整してください。

以上で完了です。

 

動作イメージ

実際に動作させた場合のイメージはこちらの動画のようなイメージになります。

 

今後改善したい事

  • PowerAutomateを使わずにAPIをよぶ
    • できるかな?
  •  ピン留めの解除
  • レスポンシブ対応
    • 今回雰囲気でコンテナを使ってみましたがレスポンシブではありません。

 

さいごに

"ピン留めメッセージがもっとアクセスしやすかった便利じゃないかな?"のアイデアだけで突っ走って作ってみました。アイデア先行でアプリとしてはまだまだ作り込みが必要なレベルかと思います。

今回Teams統合オブジェクトを使用して現在のチャネルのIdと一般チャネルのIdを取得しています。Teams統合オブジェクトはアプリのプレビューでは値が取得できません。まずはじめはTeams統合オブジェクトを使わずにチーム・チャネルを指定する機能をつけてテストを行うと捗りました。

通常アプリプロトタイプ

 

参考にしたページ

色々な有用な情報を公開していただいている皆さんに感謝です。

PowerAppsでのJSONのパースについて

koruneko.hatenablog.com

 

anko7793.com

 

learn.microsoft.com

 

 

Teams統合オブジェクトについて

learn.microsoft.com

 

hostClientTypeの値について

learn.microsoft.com