【4】MicrosoftGraphさわってみた。(PowerAppsとMicrosoftGraphと私と。) ~届け。MicrosoftGraphを始める人へ~
ここまでたどり着くとは
結構やるじゃねぇかぁ
お前さんがどーやって辿り着いたかは知らねぇが、
楽な道のりじゃなかったことはわかってる。
はなむけと言っちゃあなんだが、
俺のとっておきを見せてやるよおっ!
準備はいいかぁ!?
漢の魂、見せてやるぜぇ!
はいはい。
どうもこんにちわ。
アキヒサですね。
そろそろ覚えてもらえましたかね、
私の事を。
そうです。
IT初心者向けのブログを
ただひたすらに書きなぐっている、
アキヒサですよ。
いつの間にやら年の瀬だね!
メリークリスマス!
今日は アキヒササンタ さんからプレゼントがあるよ!
ちょっと、でかすぎてアレだから、
そこはホントごめんね!
あとで出てくるけど、こんな感じのプレゼントだよ!
今日はまず、
一言いいたい。
いや、なんなら今日だけじゃなく毎日言ってる気はするんだけど、
それでもなお言いたい。
どうする?
言っちゃう?
やめちゃう?
うん、言っちゃうね。
つれぇ~
(辛い。ツラい。 の、若者言葉)
ん?
何がって?
逆に聞こうじゃない。
ツラくねぇのけ?
君は。
全然ツラくない日なんてあんのけ?
マジかよ。
あんのかよ。
すげえな。
褒めたたえたい。
あわよくば、取り換えて欲しい。
私とアナタの人生丸ごと。
どうだろうか。
3000円出そう。
いや、丸ごととりかえてもらって3000円じゃアレだよね。
3300円でどうかね。
税込み価格だ。
なんで僕がこんなにツレェツレェ言ってるかって、
基本的には、
もう全部あの子のせい。
すごく優秀だったり
めちゃんこ有能だったり
運動神経抜群だったり
時には誰かを
知らず知らずのうちに
傷付けてしまったり
失ったり
して初めて犯した罪を知る
そう。
MicrosoftGraphのこと
だね。
なんなら、それにプラスして
PowerAutomate
PowerApps
達もそうだよね。
本っ当にもう
今の僕には何ができるの
何になれるの
誰かのために生きるなら
正しいことばっかり言ってらんないよな。
状態。
PowerApps と PowerAutomate と MicrosoftGraph という武器を
携えた状態の僕に、一体何ができるというのか。
マジで意味わかんない。
こんな感じでMicrosoft365の世界をさまよっている
そんなアナタの為のブログです。
さあ
まっさらに生まれ変わって
人生1から始めようか
このブログならそうなれる気がする。
普通の技術ブログよりも、
だーいぶ
やさーしく
説明している(つもりだ)から
じゃ、そろそろ本題行こうかね。
ひぁうぃごぉー
ひぅぃらっけぇごぅまー
~~~ 本題 ~~~
※注※
本内容は私個人の意見や見解等であり、大変恐縮ですが記載内容に関して
誤りがある可能性がございます。
そのような場合、御連絡いただけましたら早急に訂正いたしますので、
よろしくお願いいたします。
さて。じゃあ今回は、前回(3部作の3話目で)予告しておいた
会議室の使用状況を確認できる
PowerAppsアプリの作り方
を本題にぶっこんでいくよ!
で、もう今回は最初に「どんなものが出来上がるか」を御覧いただこう。
こんな感じ。
実際に動いている動画は名前とか出ちゃうのでお見せできないけど、
作り方を 1~100まで書くので、ご容赦ください。
でもね。
つまりね。
今回のブログは、以前にくらべてもとても
長い。
読み終わるまで
2日くらいかかると見込んでてください。
すっっっっっっごいなっっっがい。
もうね、
ちょっとした小論文くらい長い
覚悟しておいてほしい。
わかるよ。
前回までの3部作もそこそこの長さだったもんね。
下手すると読み終えるのに2年かかるんじゃないかと思う。
だって、実際に実用可能なモンが一個出来ちゃうくらいだから。
たーだーしー!
ここで書いている内容は、
あくまで私が色んな著名の方々のブログや、
脳内で
「こーやったら出来るんでねぇか。」
「まあ、正解じゃなくてもやってみっぺか。あ、出来たやん。」
くらい非効率な実装方法だったりする箇所だらけで、
実運用には耐えられない可能性すらある。
なので、実現が可能だとしても実装方法に関しては、
本当に一般人(市民開発者)が試行錯誤して、
かろうじて形に出来たレベルの物
であることを忘れてはならない。
では、どうやっても「簡単」には出来ないが
以下に大きく分けた手順を書き記したいと思う。
~本日のメニュー(超簡易版)~
0.Azureでアプリを作る(前回3部作のブログを参照)
1.PowerAppsの画面を作る(3画面)
2.PowerAutomateを作る(1個)
3.PowerAppsの画面で取得データをいじる
4.PowerAppsの画面をデコる
どうだい?
難しそうだろう?
え?
そうだね。
もう少し詳しい説明がいるよね。
やさしく教えてあげるね。
「おにいちゃん」って呼んでもいいんだよ。
~本日のメニュー(簡易版)~
0.Azureのアプリを作る
0-1.アプリに対して特定の権限付与。
1.PowerAppsの画面を作る(3画面)
1-1.ホーム画面作成
1-2.一覧画面作成
1-3.詳細画面作成
2.PowerAutomateを作る(1個)
2-1.PowerAutomateの大枠作成
2-2.会議室の一覧の取得方法を実装
2-3.各会議室のスケジュール取得方法実装
2-4.情報取得結果をPowerAppsへの連携実装
3.PowerAppsの画面でデータいじる
3-1.ホーム画面に何かしら実装
3-2.一覧画面でギャラリーに表示するデータの実装
3-3.詳細画面に表示するデータの実装
4.PowerAppsの画面をデコる
4-1.ホーム画面にロゴをバーン
4-2.一覧画面に動画をズドン
4-3.詳細画面に動画とか画像とかをドシャーン
どうかな?
これで少しはイメージが湧いたかな?
めんどくさそうだよね。
でも、こんなもん一回作っちゃえば
あとはどうとでも改善したりできるし、
今回だけ頑張っちゃおうよ。
ね。
おにいさんが優しく教えてあげるから。
ほら。
ねぇ。
ねぇってば。
ほらぁっ!
と、いうことでね、実際の実装方法を書いていこうと思います。
例によって、ところどころ書くのに飽きて脱線した内容が出てくるので、
最低限 ★★★ のマークの箇所だけ淡々と実装していけば、
サクッと出来上がる様に出来てると思います。
0.Azureのアプリを作る
これに関してはちょっとめんどくさ前回やったばかりなので
基本的には前回の3部作のブログを御覧いただくとして、
付与する権限の箇所が若干違うので、
★★★~
3部作の【2】nagoyaitadmin.hatenablog.com
を、御覧いただきながら
「APIアクセスの許可要求」
の権限付与の箇所だけ
以下の様に変えてください。
~★★★
~権限の付与対象~
◆User.Read.All
・すべてのユーザーの完全なプロファイルの読み取り
ユーザーの代わりに、アプリで組織内の他のユーザーのプロファイル プロパティ、部下、および上司の完全なセットの読み取りを実行できるようにします。
◆Directory.Read.All
・ディレクトリ データの読み取り
アプリで組織のディレクトリ内のデータの読み取りを実行できるようにします。
◆Place.Read.All
・会社全体の場所の読み取り
ユーザーの代わりに、アプリで予定表のイベントやその他のアプリケーション用の会社の場所 (会議室や会議室一覧) の読み取りを実行できるようにします。ユーザーの代わりに、アプリで予定表のイベントやその他のアプリケーション用の会社の場所 (会議室や会議室一覧) の読み取りを実行できるようにします。
◆Calendars.Read.All
・予定表の読み取り予定表の読み取り
アプリで予定表内のイベントの読み取りを実行できるようにします。アプリで予定表内のイベントの読み取りを実行できるようにします。
◆Schedule.Read.All
こんな感じでね、付与しておいてください。
いい子の君なら以前のブログ見ながら設定できるはずだ。
自信を持ってやってみよう。
1.PowerAppsの画面を作る(3画面)
さあ、それではさっそく始めていきましょうね。
PowerAppsでキャンパスアプリを一から新規作成してください ★★★
PowerAppsの新規作成画面にいけるかな?
この時点で「言ってる意味が全くわからない」的な子は、
僕の前のブログを最初っから最後まで読み漁ってみてね!
読み漁ってくれた上で、まったくわからなかった場合は、
以下のブログをもう一度読んでみてね★
1-1.ホーム画面作成
まず一つ目は、ホーム画面だね。
アプリを開いた時に開く画面を用意するよ。
★★★~
まずはスクリーンの名前を変えてあげようか。
Screen1 だと味気ないから。
じゃ次はホーム画面らしく、適当な画像を背景に設定してあげよう。
そしたら画像を画面いっぱいまで広げて、
表示する背景画像を指定しよう。
~★★★
ふふふ。
なんかシャレオツじゃない?
以下のサイトで画像を作成してみました。
決して宣伝ではない。
私には、お金は一円たりとも入らない。
じゃあ、背景だけあってもしゃーないので、
ボタンを追加して「会議室一覧」とでも表記を変えてみよう。★★★
はい。
1つ目の画面作成は一旦ここで終わり。
簡単だね!
さすがPowerAppsさんやでホンマ。
注)あとでややこしい事をこの画面に施しますので、慢心されませんよう。
ただ、ここでもう一個だけ実施しておきたい事がある。
保存。
画面左上の「ファイル」から、しっかりと保存しておいてあげてね。
一回ちゃんと保存しておけば、
後続の作業は定期的に自動保存しておいてくれるからね。
さすがPowerAppsちゃんだぜ。
1-2.一覧画面作成
よーし来た。
一覧画面ね!
会議室の一覧を表示させるところね!
じゃあアレだね。
★★★~
新しい画面 で リスト を選択したら良さそうだね!
はい出たこれ。
つまらないね!
ここでも、後でわかりやすくするためにも、色々と名前を変えておこうね。
ViewScreenだとかさ。色々とさ。
~★★★
それに、多分会議室の画像なんて、
とりあえずいらないであろう事にして、
文字列だけの構成にしたい。
また、一画面で4つしか表示できないんじゃ
スクロールして最後まで到達するまでに手首折れちゃうよね。
★★★~
画面右の プロパティ から レイアウト を変えて、
その上で 折り返しの数 を2にしてみようか。
~★★★
※後で言うけど、ここはタイトルともう一つだけで良かった。
最終的にフィールド一個余分になっちゃった。
ぃよしっ!
まずはこんぐらいでいいかな。
デザインは最後にぶちかまそう。
どうだい?
ここまでで少しはこのアプリのイメージをつかめてきたかな?
アプリを開いて、
ボタンを押したら、
会議室の一覧画面が表示される
みたいな流れだね。
そうだね。
聞き分けが良い子は好きだよ、僕は。
好きだよ。
好きだよ。
1-3.詳細画面作成
ゴホンッ!
じゃ、次だね。
もう最後だね。
僕と力を合わせて詳細画面を作ろう。
んー。
何がいいかなー。
★★★~
画面の新規作成
空(から)の画面でいっか。
~★★★
めんどくせぇし。
ね。
やっちゃお。
やっぱりいいよね。
シンプル伊豆ザベスト。
伊豆行きてぇー!
魚を食いてぇー!
海鮮丼をー!
失礼。
取り乱しました。
でも、とりあえずスクリーン名変えてあげたら、
まだ何もしなくてもいいんだけどねー。
でもそれだとさすがにイメージ付きづらいだろうから、
★★★~
ギャラリー を一個表示してあげとこうかしらね。
ただ、左っ側にこんなもんあると邪魔くさい気がするから、
一応右の方に持っていこう。
んで、まあ画像もいらないから、またレイアウト変更しよう。
折り返しの数はここは1のままでいいかな。
~★★★
はい。
終わり。
そう。終わりだよ。
画面作成は。
PowerAppsさんにかかったらこんなもん2びょ・・・いや5秒で終わりよ。
機能はこっからつけてくんだからね。
さあ・・・地獄の始まりだぜ!
ついてこいよ!
しっかりつかまって!
そう、もっと!
もっと!もっとつかまって!
ぎゅっと抱きしめて!
離さないで!
2.PowerAutomateを作る(1個)
さて。
じゃあこっからは地獄をお届けするよ。
覚悟・・・しといて欲しいんだけど、
正直、もう前回までのブログの3部作を
しっっっっっかり読んでいただいている方には、
余裕。
だし、読んでなくても、★★★の部分だけやってもらえれば
何も考えなくてもOK。
気付いたら出来上がってっから。
楽勝だべ?
じゃ行こう。
と言いつつ、まずは最初に今回作るPowerAutomateの全貌を御覧いただこう。
Apply to each の中に色々あったりするし、
画像だけじゃなんだから、
全体を通して何をやっているのかを軽く教えておこう。
<今回作るPowerAutomateの内容の概要(だいぶ端折ってるけど)>
0.PowerAppsのボタンをきっかけにこのPowerAutomateが実行される。
1.このテナント上にある会議室名をすべて取得する。
2.以下の内容をすべての会議室毎に実施。
2-1.取得した会議室の情報を取得する(会議室の建物名とか定員数とか)
2-2.今の時間から24時間以内に予定されている予定を全部取得する。
3.取得した情報をPowerAppsに渡してあげる。
これだけ。
2-1.PowerAutomateの大枠作成
早速PowerAutomate・・・・なんだけどさ。
まだPowerApps開いてくれてるよね?
実はPowerAppsから作りたいのよ。
PowerAutomateを。
あー大丈夫大丈夫。
一瞬だけわけわかんなくなるよね?
「どっちだよ!」
「両方ともPowerA・・・で始まるし!」
って言いたくなる気持ちはわかる。
でも、すまねぇ。
PowerAppsからPowerAutomateを呼び出す時は、
こうやっても出来るんだぁへぇー
って覚えてくれればそれでよし。
★★★~
さっき作った 会議室一覧 ボタンを選択して、
アクション から PowerAutomate を選択すると、
画面右側に新しい何かがピョロっと出てくるから、
そこで「新しいフローの作成」を押してほしい。
~★★★
どうだい?
こんな感じの画面が出たかい?
★★★~
そしたら左上にある(かどうかは定かではないが)
「PowerAppsボタン」
ってのがあるだろう?
それを選択しよう。
~★★★
こんな画面が出たはずだ。
この後に関しては前回のブログ、3部作の【3】
の記事を読んできてくれた君ならある程度覚えておいてくれていると思う。
その前提でちょっとスピード上げて書いていくね。
★★★~
まずは変数の初期化。
名前は RoomMessage にしましょうか。
種類は 文字列 を選択。
~★★★
ちょっとネーミングセンスが無い気がするが、
僕はもうこれでいく。
PowerAutomateResult みたいな方が良かったかなーとは、思ったりもするけど。
★★★~
次はスケジュールの有無確認。
RoomSchChk という名前にしてみました。
種類は文字列。
~★★★
これは、各会議室毎に24時間以内にスケジュールがあるかどうかを
判断するためだけのフラグだと思ってくれれば良い。
続いては会議室の定員数用の変数だ。
★★★~
名前は RoomCapacity
種類は文字列。
~★★★
さて。一先ずここまでで下準備が完了。
あとは、メインとなる全会議室の取得と、
その会議室毎のスケジュールを取得してくるだけだ。
どうだい?
まだついてこれているよね?
地獄はここから先だぜぃ!
2-2.会議室の一覧の取得方法を実装
これね。
どんだけ大変なんだろうって思うじゃんね?
心してかかれ。
早速やってみよう。
★★★~
「新しいステップ」を押した状態で、
会議室
~★★★
と入力してみよう。
出てきた選択肢から「会議室の取得」を選択してごらん。★★★
ん?
何コレ。
何コレ珍100景状態。
じゃあ、
★★★~
この状態で一旦保存してみようか。
んでテストしてみよう。
~★★★
なんか出てきた。
よくわかんないけど「続行」してみる。★★★
※ちゃんと読んでみると色々書いてあるから真面目な人はそこを読んでね。
「続行」を押すと・・・
今度は「フローの実行」が出てきやがった!
同じような事何回もさせやがって!
このような事象を、マトリョーシカ現象 と呼びます。(僕の中でだけ)
押してやんよ!おら!
「フローの実行」 ★★★
をよぉ!
なんだよ。
あっさり成功したじゃねぇか。
んじゃ「完了」ボタンも押してやるか。 ★★★
すると、画面が若干更新されてこんな感じになる。
そしたら作成した「会議室の取得」を押してみよう。 ★★★
わー。
とれてるー。
全部の会議室の情報(name と address)がとれてるやないかーい。
と、いうことで、2-2は完了。
全然地獄じゃなかったね。
ここはね。
まだ。
2-3.各会議室のスケジュール取得方法実装
さて。
ドMの皆様。
待たせてごめんなさい。
お待ちかねの地獄ですよ。
こっからはマジで覚悟してください。
会議室の一覧は取得できたから、
それぞれの 定員数 や 24時間以内に予定されているスケジュール
を取得してあげる必要がありますからね。
ここからは時間無い時は確実に★★★の部分だけでかまわないと思います。
★★★~
じゃあ早速新しいステップ追加して、
Apply
と入力して
Apply to each
を選択してみてください。
~★★★
このApply to each は、いわゆるループだね。
Apply to each を選択して表示された入力欄にカーソルを合わせると、
こんな感じで右側に例のおせっかい便利なあの子が現れる。
「動的なコンテンツ」の「会議室の取得」にある「値」を選択しよう。 ★★★
これで「会議室の取得」で得た 値 分の回数処理を実行してくれるんだね。
さて、次は、この状態から
Apply to each の中にある「アクションの追加」 ★★★
を選択してみよう。
その上で、HTML to text を選択してみよう。 ★★★
※ちょっとここは本当にごめんなさいなんだけど、
僕は何故かHTML to textを使ってるんだけど、
これも最初に変数セットしておいてあげたらよかったかも。
HTML to text が表示されたら、中に
★★★~
?StartDateTime=
って記入して、式のところから utcNow() を選択する。
~★★★
★★★~
続けて、utcNowの後にカーソルを合わせて
&endDateTime=
って入力して、もう一回、式のところに
addDays(utcNow(), 1)
って入力してOKを押してください。
~★★★
こんな感じ↓になればOK。
さて、今は一体何をやったかと説明すると、
現在の日時(取得するスケジュールデータの開始時)と
24時間後の日時(取得するスケジュールデータの終了時)を
変数として指定したんですね。
後で出てくる Graph用のロジック に使う文字列をここで指定してるよ!
★★★~
後でややこしくなるからここの名前も変えてあげましょう。
UTC とでもつけてあげてください。
~★★★
我々日本の場合は+09:00ですね。
これがね、けっこうやっかいでね。
PowerAutomateでスケジュール取得したりする場合って、
この協定世界時の時刻で取得しちゃったりするんですよ。
だから、ここらへんをしっかり考慮してあげないと、
出来上がった時に
「・・・?3時間前に終わった会議が今表示されてるやん」
とかになったりするのですよ。
やっかいですよね。
なので、次にまた日本時間を定義するステップを追加してあげたいんですが、
若干めんどくさいですよね。
なので、ここはちょっとだけ楽しましょう。
※よく考えたら、ここの「UTC+9」ってステップはいらないかも。
後々式の中で東京時間用にConvertTimeで東京時間してるから。
★★★~
今作った HTML to text の右上の・・・をクリックして
クリップボードにコピー というやつを選択しましょうかね。
~★★★
★★★~
そしたら「アクションの追加」を押した後の
「アクションを選択してください」の画面で、
一番右の「自分のクリップボード」を選択してみましょう。
~★★★
そう。選べるんですねー。
ステキですねー。
当然コピーした内容そのままじゃいけないので編集しましょうね。
じゃあ、これをどう編集するかというと、
★★★~
もうここはこのブログからのコピペで御利用ください。
まずはStartDateTime=の後の式の編集。
convertTimeZone(utcNow(), 'UTC', 'Tokyo Standard Time')
に変えて更新してください。
~★★★
★★★~
次はもう一個endDateTimeの後の式。こちらは
addDays(convertTimeZone(utcNow(), 'UTC', 'Tokyo Standard Time'), 1)
に変えて更新してください。
~★★★
ここで「取得するスケジュールの対象」を24時間後と指定してるわけ。
まあ、最初の UTC の設定値を、東京用に直しただけだね。
さて、更新できましたか?
PowerAutomateの不具合なのか、
僕のPCのせいなのか、
僕のスピードが速すぎてついてこれないのか、
「更新」ボタンを押しても
更新されていないことがあったりするので、
何回か確認してあげてください。
出来ればこっちも名前を変えてあげてください。
UTC+9
とかに。
さて・・・大丈夫?
ここらでちょっと休憩しとく?
え?
あっ
だっ、大丈夫大丈夫!
ほんと、休憩するだけだから!
ねっ!何もしないから!
ねぇっ!
ガチで休憩するだけだし!
ねぇ・・・ん?僕の後ろに何かある?
あ、部長・・いや違うんですこれはその別にあの本当に休けゴメンナサイ
えー、うぉっほん
ゴホッゴホン。
じゃあ次のステップはMicrosftGraphを使って
会議室のメールアドレスを取得したいと思います。
ここらへんは前回のブログに書いてある内容だね。
★★★~
HTTPを選んで以下の文字列を入力して
https://graph.microsoft.com/v1.0/users?$filter=startsWith(mail,'
「会議室の取得」の「値 アドレス」を選択。
~★★★
選択したらその後に ') (シングルコーテーションと半角右カッコ)だけ
忘れずに追加。 ★★★
で、他の項目についてはどうやるか覚えてるかな?
「詳細オプションを表示する」を押して、なんちゃらかんちゃらだよね。★★★
詳しくは前回のブログ【3】を見ようね!
クライアントIDとかテナントIDとか、シークレットとか指定するやつね!
名前も変えておいてあげた方がいいかな。
Graphでユーザー情報取得
とかかな。
そしたら次はおなじみのステップ「JSONの解析」さんの出番だね。★★★
ここでのスキーマの取得方法も前回のブログ【3】を確認してね!
まあ。。。今回だけはしゃーなし。
書いておいてあげよう。
===JSONの解析 用のスキーマ===★★★
{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"businessPhones": {
"type": "array"
},
"displayName": {
"type": "string"
},
"givenName": {},
"jobTitle": {},
"mail": {
"type": "string"
},
"mobilePhone": {},
"officeLocation": {},
"preferredLanguage": {},
"surname": {},
"userPrincipalName": {
"type": "string"
},
"id": {
"type": "string"
}
},
"required": [
"businessPhones",
"displayName",
"givenName",
"jobTitle",
"mail",
"mobilePhone",
"officeLocation",
"preferredLanguage",
"surname",
"userPrincipalName",
"id"
]
}
}
}
}
=====
さて、じゃあ次だ。
次は前回のブログには書いてない。
けど、応用編だね。
今取得した会議室の情報を
「ユーザー」としてではなく
「会議室」として
取得するGraphの書き方。
ややこしいよね。
例えばユーザー情報としてメールアドレス
Room1@Akihisa.com
の情報をGraphで取得するとこんな感じなんだけど、
Graphでユーザーとして情報を取得する文字列はコレ
GET https://graph.microsoft.com/v1.0/users/Room1@Akihisa.com
== ユーザーとしての情報 ==
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": ,
"displayName": "会議室1",
"givenName": null,
"jobTitle": null,
"mail": "Room1@Akihisa.com",
"mobilePhone": null,
"officeLocation": "東日本",
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "Room1@Akihisa.com",
"id": "63********5"
}
====
Graphで会議室として情報を取得する文字列はコレ
GET https://graph.microsoft.com/v1.0/Places/Room1@Akihisa.com
会議室として情報を取得すると
== 会議室としての情報 ==
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#places/$entity",
"@odata.type": "#microsoft.graph.room",
"id": "30********a",
"displayName": "会議室1",
"geoCoordinates": null,
"phone": "",
"nickname": "会議室1",
"emailAddress": "Room1@Akihisa.com",
"building": "***Building",
"floorNumber": 6,
"floorLabel": null,
"label": null,
"capacity": 5,
"bookingType": "standard",
"audioDeviceName": null,
"videoDeviceName": null,
"displayDeviceName": null,
"isWheelChairAccessible": false,
"tags": ,
"address": {
"street": "",
"city": "名古屋市",
"state": "愛知県",
"countryOrRegion": "Japan",
"postalCode": "***-****"
}
}
====
こんなにも取得できる情報量が変わってくるわけ。
意味わかんないよね。
お気持ちは察します。
ユーザーとして情報拾ってくる時にも、
会議室かどうか判断して情報全部入れちゃえよ
って思いますけどね。
しょうがないと割り切りましょう。
じゃあ実際に会議室としての情報を取得する
MicrosoftGraphの書き方を含め書き綴っていきましょうかね。
まずはさっきと同じ。
★★★~
HTTPのステップを追加してくださいな。
んでURIのところでは以下の文字列を入力して「値 アドレス」を選択。
https://graph.microsoft.com/v1.0/places/
~★★★
この https://~~Places/メールアドレス(またはID) で、
会議室としての情報を取得できるのよ。
さて、どうだろうか。
ここで頭が切れる方はさっき使った「クリップボードにコピー」
を使って楽できたのではないだろうか。
素晴らしい!
天才!
僕は全部手動でやりました!
自分で書いてて今気付きました!
ちくしょう!!
じゃあHTTPの後は例によってJSONさんのお出ましをしてもらおう。★★★
おおっと。
キミキミキミ。
今もしかして・・・もしかしてだけど。
クリップボードにコピーして作っちゃったりしたかい?
申し訳ねえ!
ここではそれは使わない方が良いんだ。
何故かとゆーと、前回使ったJSONさんのステップでは、
「Graphでユーザー情報取得」のHTTPの値を参照してるよね。
でも今回のJSON解析では、
参照先は今作った「Graphで会議室として情報取得」だから。
むやみやたらにコピーすると危ないということにも気付けたかな?
え?
「アキヒサさんは、そういう初心者が陥りがちな罠を
しっかりサポートしてくれるから助かる」
って?
ありがとう。
なんたって、僕が今そうやって間違えたところだからさ。
どちくしょうめが!!
さて。
作ってくれたJSON解析では、
★★★~
「Graphで会議室として情報取得」
の 本文 を指定してくれたとは思うんだけど、
~★★★
スキーマがまたわからないよね。
今回も特別に以下に記載しておくけど、
ブログ【3】でのスキーマの取得方法もしっかり覚えておいてね!
== 会議室としてのJSON のスキーマ ==★★★
{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"@@odata.type": {
"type": "string"
},
"id": {
"type": "string"
},
"displayName": {
"type": "string"
},
"address": {},
"geoCoordinates": {},
"phone": {
"type": "string"
},
"nickname": {
"type": "string"
},
"emailAddress": {
"type": "string"
},
"building": {},
"floorNumber": {},
"floorLabel": {},
"label": {},
"capacity": {
"type": "integer"
},
"bookingType": {
"type": "string"
},
"audioDeviceName": {},
"videoDeviceName": {},
"displayDeviceName": {},
"isWheelChairAccessible": {
"type": "boolean"
},
"tags": {
"type": "array"
}
}
}
====
OKかい?
親切でしょう?
もっと、あがめたてまつっても良いんですよ?
なんなら趣味と備忘録としてしか書いてないんだからこのブログ。
1円も入ってこないんだから!
そろそろMicrosoftさんから、お金もらってもいいんじゃないだろうか。
ユーザー促進できましたで賞的な。
MVPとかの称号は別によいので・・・マニーを・・・
いえ、もらえるなら何でもいただきます。
ごめんなさい。
ください。
続きいこうか。
次はいよいよ実際にその会議室が
24時間以内に予定しているデータを取得するよ!
★★★~
じゃあ、まずはHTTPのステップを追加してほしい。
URIの値はこんな感じだよ!
文字列:https://graph.microsoft.com/v1.0/users/
式:first(body('ユーザー情報JSON')?['value'])?['id']
文字列:/calendarview
動的なコンテンツ:UTCのThe plain text content
~★★★
これはまたクリップボードでコピーして作れるね。
いちいちテナントIDとかシークレットとか入力するのめんどいからね。
さて、じゃあおなじみJSONさんの出番ですね。
次は当然、今作ったHTTP(上記画像だと「予定情報取得」の「本文」)を
参照させてください。★★★
スキーマはこんな感じで
== 予定情報解析 のスキーマ==★★★
{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@@odata.etag": {
"type": "string"
},
"id": {
"type": "string"
},
"createdDateTime": {
"type": "string"
},
"lastModifiedDateTime": {
"type": "string"
},
"changeKey": {
"type": "string"
},
"categories": {
"type": "array"
},
"transactionId": {},
"originalStartTimeZone": {
"type": "string"
},
"originalEndTimeZone": {
"type": "string"
},
"iCalUId": {
"type": "string"
},
"reminderMinutesBeforeStart": {
"type": "integer"
},
"isReminderOn": {
"type": "boolean"
},
"hasAttachments": {
"type": "boolean"
},
"subject": {
"type": "string"
},
"bodyPreview": {
"type": "string"
},
"importance": {
"type": "string"
},
"sensitivity": {
"type": "string"
},
"isAllDay": {
"type": "boolean"
},
"isCancelled": {
"type": "boolean"
},
"isOrganizer": {
"type": "boolean"
},
"responseRequested": {
"type": "boolean"
},
"seriesMasterId": {},
"showAs": {
"type": "string"
},
"type": {
"type": "string"
},
"webLink": {
"type": "string"
},
"onlineMeetingUrl": {},
"isOnlineMeeting": {
"type": "boolean"
},
"onlineMeetingProvider": {
"type": "string"
},
"allowNewTimeProposals": {
"type": "boolean"
},
"isDraft": {
"type": "boolean"
},
"recurrence": {},
"onlineMeeting": {},
"responseStatus": {
"type": "object",
"properties": {
"response": {
"type": "string"
},
"time": {
"type": "string"
}
}
},
"body": {
"type": "object",
"properties": {
"contentType": {
"type": "string"
},
"content": {
"type": "string"
}
}
},
"start": {
"type": "object",
"properties": {
"dateTime": {
"type": "string"
},
"timeZone": {
"type": "string"
}
}
},
"end": {
"type": "object",
"properties": {
"dateTime": {
"type": "string"
},
"timeZone": {
"type": "string"
}
}
},
"location": {
"type": "object",
"properties": {
"displayName": {
"type": "string"
},
"locationType": {
"type": "string"
},
"uniqueIdType": {
"type": "string"
},
"address": {
"type": "object",
"properties": {}
},
"coordinates": {
"type": "object",
"properties": {}
}
}
},
"locations": {
"type": "array"
},
"attendees": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"status": {
"type": "object",
"properties": {
"response": {
"type": "string"
},
"time": {
"type": "string"
}
}
},
"emailAddress": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"address": {
"type": "string"
}
}
}
},
"required": [
"type",
"status",
"emailAddress"
]
}
},
"organizer": {
"type": "object",
"properties": {
"emailAddress": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"address": {
"type": "string"
}
}
}
}
}
},
"required": [
"@@odata.etag",
"id",
"createdDateTime",
"lastModifiedDateTime",
"changeKey",
"categories",
"transactionId",
"originalStartTimeZone",
"originalEndTimeZone",
"iCalUId",
"reminderMinutesBeforeStart",
"isReminderOn",
"hasAttachments",
"subject",
"bodyPreview",
"importance",
"sensitivity",
"isAllDay",
"isCancelled",
"isOrganizer",
"responseRequested",
"seriesMasterId",
"showAs",
"type",
"webLink",
"onlineMeetingUrl",
"isOnlineMeeting",
"onlineMeetingProvider",
"allowNewTimeProposals",
"isDraft",
"recurrence",
"onlineMeeting",
"responseStatus",
"body",
"start",
"end",
"location",
"locations",
"attendees",
"organizer"
]
}
}
}
}
====
いや、なっげぇ!
なんだよこれ。コピペすんのもめんどいよね。
ごめんねぇ。
このブログが長いと感じてるのも、これのせいだから。
僕のせいじゃないから。
そろそろHTTPとJSONさんのかけっこも飽きてきたよね。
二人のかけっこはもう終わりだから大丈夫。
次いこうね。
そして、この地獄もそろそろ終わりだよ!
このPowerAutomate地獄は・・・ね・・・
次のステップは「変数の設定」です。★★★
もう何も考えず、こんな感じで設定してみてください。
★★★~
最初に初期化しておいたRoomSchChkの変数に以下の文字列で
式を書いてください。
first(body('予定情報解析')?['value'])
~★★★
そしたら次のステップでは、プログラムを経験すると必ず通る
条件分岐をね。してもらうのよ。★★★
★★★~
「条件」を選択したら、こんな感じで設定してあげてください。
動的なコンテンツ:RoomSchChk
次の値に等しい
値の選択:空白のまま
~★★★
これは、一つ手前の確認用フラグの値がどうなってるか。
空白か否かで条件を指定してるんですね。
つまり、この会議室には24時間以内に
予定なんもありませんよー!ってことなのか、
予定ある!書き出す!なのかってこと。
条件が設定できたら、まずはYESの場合の処理を書いてしまいましょう。
ちょっとややこしいからご注意を。
★★★~
変数に文字列追加 のステップを作成して、
名前:RoomMessage
値:後述
~★★★
★★★~
値に関しては、まず最初に以下の文字列を式として入力してほしい。
first(body('ユーザー情報JSON')?['value'])?['mail']
(この会議室のメールアドレスを取得しているんだね。)
そしたら次に #(シャープ)を打って、
動的なコンテンツ「会議室としてのJSON」の「Building」を選択しよう。
~★★★
Buildingはそのままの意味。
会議室情報にビル名が登録されていたら、その値をとってきます。
★★★~
そしたら次は ((半角スペースと半角左カッコ) を打って、
動的なコンテンツ「会議室としてのJSON」の「FloorNumber」を選択しよう。
~★★★
これもそのまんまの意味だよね。
階数が登録されていれば、
その値をとってきてあげる親切設計にしています。
★★★~
そしたら次は F)(Fと半角右カッコ) を打って、
また式に以下の文字列を入力してもらいたい。
first(body('ユーザー情報JSON')?['value'])?['displayName']
~★★★
階数をとって3とか5とか表示しても「は?何?」ってなりそうだから、
とってきた値にFを付けて 3F とか 5F とかになるようにしてあげました。
最後は、会議室のお名前(表示名)ね。
どうだろう。
★★★~
そしたら次は 定員:(全角スペース定員コロン) を打って、
動的なコンテンツ「会議室としてのJSON」の「capacity」を選択しよう。
~★★★
これもわかりそうだね。
会議室の定員数。
6人で会議したいのに、定員4人の会議室は選びたくないもんね。
なんて親切なんでしょう。このシステムは。
★★★~
そしたら最後は直接 名#予定はありません` (末尾の ` はバックコーテーション)
みたいな文字列を入力したら
YES(予定がなかった)の場合の文字列成型は完了だ。
~★★★
この ` (バックコーテーション)で、
A会議室のRoom情報と24時間以内の予定情報
と
B会議室のRoom情報と24時間以内の予定情報
を区切っています。
' (シングルコーテーション)ではないんです。
わかりづらいモン使ってすんません。
いやー長いね。
ツラいね。
もう少し頑張ろっか。
もう9合目まで来てるから。
あと1合くらいだよ。
じゃあ、次は条件分岐のもう片方の方ね。
ここで、ここまで頑張ってついて来てくれたアナタたちに贈る。
必殺技を教えてあげる。
★★★~
さっき、YESの場合の条件作ったじゃない?
アレを全部コピーするの。
~★★★
で、Ctrl+Vでいいえの場合の方に貼っちゃうの。 ★★★
できるもんだねえー。
やってみるもんだねぇー。
伝家の宝刀、こぴぺ。
でも当然NOの場合は違う事書かなきゃだよね。
だから、こんな感じ↓で編集しちゃってくれさい。
文字列末尾の「予定はありません`」を消す。★★★
★★★~
そしたら次にもう一回 Apply to eachのステップを追加して、
値に「動的なコンテンツ」の「予定情報分析」の「Value」を指定してほしい。
~★★★
ここからが、24時間以内に予定されているスケジュールを取得するロジックだね。
★★★~
じゃあ次は「アクションの追加」から、例によって「文字列変数に追加」を選んで。
RoomMessage に 動的コンテンツの「予定情報解析」の「Subject」を選択だ。
~★★★
会議室の予定のSubjectって値に、
予定を作成した人の名前か、もしくは会議の件名がセットされてるから、
それを取得してこようってロジックだね。
この値を画面表示用に取得してるよ。
★★★~
そしたら続きに以下の文字列を入力して、
$$予約者(または件名):
またもっかい同じJSON解析値をセットしよう。
~★★★
ここで、実際にPowerAppsにデータが渡った時に
データの区切り文字として $$ という文字列を使ってるだけです。
特に $$ に意味はありません。
★★★~
そしたら次は全角で ;(セミコロン) 入力して、また式を以下の文字列を
一行で書いてください。
convertTimeZone(substring(string(item().start), 13, 19), 'UTC', 'Tokyo Standard Time', 'yyyy/MM/dd HH:mm')
↑をコピペでいいよ。
~★★★
ここで出てくる ;(全角セミコロン)も、区切り文字としてつかってるだけです。
本当、不細工プログラムで申し訳ねぇ。
このロジックで、予定されているスケジュールの開始時刻を取得してます。
ちなみに convert・・・ のこれは何をやってるかっつーと、
さっき書いてた協定世界時から日本用に時間を変更しているんだね。
しかも、ちゃんとyyyy/MM/DD HH:mm の形式にして出力してくれるように
お願してるってわけよ。
それじゃ次。
★★★~
続いて ~ (全角スペース~全角スペース)と入力してくれい。
そしてまた式で以下の文字列を設定してね。
convertTimeZone(substring(string(item().end), 13, 19), 'UTC', 'Tokyo Standard Time', 'yyyy/MM/dd HH:mm')
~★★★
このロジックで予定されたスケジュールの終わりの時刻を取得ね。
そしたら最後に ; (全角のセミコロン) を2つ、付けてください。★★★
これも最終的に値を分割するためにこんな力技でやってみています。
これでこのステップは終わり。
さ。
あと、もう一歩だよ。
★★★~
Apply to each 2 の外に再度「文字列変数に追加」のステップを作成します。
名前:RoomMessage
値:`(バックコーテーション)
~★★★
このバックコーテーションで、
各会議室のスケジュール情報
を区切る感じでコーディングしてます。
忘れないでね♡
どうだろうか。
こんな感じになったかな?
ここまでのロジックを実行するとこんな感じのデータが取得されるよ!
<データ例>
・24時間以内にその会議室にスケジュールがない場合
⇒room1@Akihisa.com# (F)第一会議室 定員:5名#予定はありません`
・24時間以内にその会議室にスケジュールがある場合
⇒room2@Akihisa.com#アキヒサビル (3F)第二会議室 定員:6名#アキ ヒサ $$予約者(または件名):アキ ヒサ ;2020/12/13 09:30 ~ 2020/12/13 10:30;;アキ ヒサ $$予約者(または件名):アキ ヒサ ;2020/12/13 14:00 ~ 2020/12/13 15:00;;`
ちょろっと説明すると、
最初の # までがメールアドレス。
そこから後ろの # までが会議室情報。
そこから後ろの $$ までがその会議室の直近の予定のSubjectの値。
$$ から 次の ; までが直近のスケジュールに表示させる予約者か会議の件名。
そこから ;; までが、その予定の開始時刻から終了時刻。
以降は24時間後までに、その会議室のスケジュールを取得し続ける感じ。
最後には ` (バックコーテーション)で締めくくり。
いやあー
よく頑張った。
本当によく頑張ったよ。
あとはもうボーナスステージみたいなモン。
気軽に楽しくエンジョイしてくれよな。
2-4.情報取得結果をPowerAppsへの連携実装
ようやくこの大項目2の終わりだね。
★★★~
このApply to each の外に新しいステップを追加しよう。
ステップの内容検索に Power って打つと
「PowerAppsまたはFlowに応答する」
ってのが出てくるから、選んでくれい!
~★★★
したら表示された画面で
直感的に
本能のままに「+出力追加」を押してみようか。 ★★★
ここは「テキスト」を選んでみよう。 ★★★
するとこんな感じの画面になるから、
値を設定してみよう。
左側の欄に「RoomListData」右側には「変数」の「RoomMessage」 ★★★
めでてぇー!
これでPowerAutomateちゃんは終わり!
終わりだよぉ!
地獄お疲れ!
休憩する?
今度こそ絶っ対、何もしないから。
ねっ!
ねっ!
いいでしょ?
休んでこ!
ええやんええやん。
な?
ええやん?
あーーーー!!疲れたーーー!!!
続き書きたくねぇーーーー!
書くけどさ。
せっかくだから。
3.PowerAppsの画面でデータいじる
さて。
PowerAutomateちゃんの実装がひと段落したから、
あとはもう余裕でしょ。
多分。
ボーナスステージの前に裏ボス存在してたらゴメン。
3-1.ホーム画面に何かしら実装
さて、ホーム画面には色々と仕掛けをしてあげる必要があるんだ。
★★★~
えー、じゃあ早速、2つのラベルを作成してほしい。
ラベルのお名前は上から
AutomateOutPut
AutomateOutPutChange
~★★★
てな感じどうかな?
さて、作ったからには中には何かしらの情報を持たせるよ。
★★★~
まずは AutomateOutPut 。
こんな感じで
//PowerAutomate出力場所
Text(RoomsListDataStr.StringData.roomslistdata)
※//はコメントアウト行だから、好きに書いてください。
じゃ次。AutomateOutPutChange。
//「会議室一覧」ボタンでの値取得元。フィールドの削除は不可
First(Split(AutomateOutPut.Text,"~")).Result
~★★★
できたかな?
出来たら小~ちゃくして、端っこの方にでもおいやっておいてください。
もしくは非表示に。
★★★~
で、次は「会議室一覧」ボタンの内容を変更するね。
ボタン押すと左上のプロパティが「OnSelect」になると思う。
ここの値をあれこれしてあげたいと思います。
OnSelectの値に以下の文字列を突っ込んでください。
やさしくね。
~ 「会議室一覧」ボタンの「OnSelect」の内容 ~
Set(RoomsListDataStr,{StringData:'PowerApps会議室一覧とスケジュール取得_202012'.Run()});
ClearCollect(RoomDataForView,Split(AutomateOutPutChange.Text,"`"));
Remove( RoomDataForView , Last(RoomDataForView.Result) );
Set(LoadFLG, "0");
Navigate(ViewScreen)
~★★★
簡単に説明すると、
PowerAutomateを作動させて
RoomDataForViewっていうコレクションの値をセットしなおして、
最後が何もデータ持ってないレコードができちゃうから
最後のテーブルだけ削除して、
会議室一覧画面へGO
って感じかな。
これ含む、以降のロジックは、
時間に余裕がある時に解読してみてください。
※ちなみに LoadFLG は、今回詳しく説明してない
「ビュー画面の更新ボタン」クリック時の色を変えるためのフラグです。
つまり Set(LoadFLG, "0"); の行は別に書かなくても命に支障はない。
さて。ここで一先ずこのページのロジックは完了。
次いこ、次。
3-2.一覧画面でギャラリーに表示するデータの実装
★★★~
最初にしてもらいたい事がある。
一覧画面に配置してあるギャラリーにデータソースを指定してあげよう。
データソース名は
RoomDataForView だ。
ギャラリーを選択した状態で画面右のプロパティから選ぶも良し、
画面左上の Items の数式バーに RoomDataForView って書いてもええで。
さっき HomeScreen のボタンでセットしたコレクションのデータだね。
データソースを指定できたら、
まずは一つ、データ保持用の非表示のテキストラベルをつくろう。
場所はギャラリーの中に作ってね。
ネーミングはそうだねえ、AutoMateResult とかどうだい?
PowerAutomateで取得した情報を持つ個所。
じゃあそのラベルにこんな感じで設定してみよう。
ThisItem.Result
名前:AutoMateResult
Textの値:ThisItem.Result
~★★★
もうデフォルトで入ってるかな?
ならいいんだ。
続いて、もう2つほどギャラリー内にラベルフィールドを作成してほしい。
AutoMateResultのサンプルデータ
Room1@aAkihisa.com# (F)会議室1 定員:6名#アキ ヒサ $$予約者(または件名):アキ ヒサ ;2020/12/13 09:30 ~ 2020/12/13 10:30;;アキ ヒサ $$予約者(または件名):アキ ヒサ ;2020/12/13 14:00 ~ 2020/12/13 15:00;
★★★~
2つラベル追加
◆1つ目
名前:MessageTrim
Textの値:Substitute(First(Split(Last(Split(AutoMateResult.Text,"#")).Result,"#")).Result,";;","`")
◆2つ目
名前:SubjectTrimNo
Textの値:Find("$$",MessageTrim.Text)
~★★★
この2つで、PowerAutomateから取得してきた文字列の羅列を
分解したりなんだりしているよ!
暇な時にでも解析してみてね♡
一応サンプルデータはこちら。
MessageTrim
アキ ヒサ $$予約者(または件名):アキ ヒサ ;2020/12/13 09:30 ~ 2020/12/13 10:30`アキ ヒサ $$予約者(または件名):アキ ヒサ;2020/12/13 14:00 ~ 2020/12/13 15:00`
SubjectTrimNo
6
とか。
★★★~
今回、レイアウトを「タイトル、サブタイトル、本文」って感じのを
選択してあるから、
上から順にこの内容で文字列を入力してくださいな。
※前述、上記2つのフィールドの値を使って色々と情報をいじっています
タイトルの部分(フィールド名:RoomNameAtView)
If(Left(Left(Mid(AutoMateResult.Text,Find("#",AutoMateResult.Text)+1),Find("#",Mid(AutoMateResult.Text,Find("#",AutoMateResult.Text)+1))-1),4)=" (F)",
Mid(Left(Mid(AutoMateResult.Text,Find("#",AutoMateResult.Text)+1),Find("#",Mid(AutoMateResult.Text,Find("#",AutoMateResult.Text)+1))-1),5),
Left(Mid(AutoMateResult.Text,Find("#",AutoMateResult.Text)+1),Find("#",Mid(AutoMateResult.Text,Find("#",AutoMateResult.Text)+1))-1))
サブタイトルの部分(フィールド名:MessageCollect)
If(SubjectTrimNo.Text="",MessageTrim.Text,
"<直近の予定>" &Char(10)& Text(Substitute(Left(Mid(MessageTrim.Text,Find("$$",MessageTrim.Text)+2),Find("`",MessageTrim.Text)-SubjectTrimNo-2),";",Char(10))))
本文の部分:フィールドごと削除る(すまん)
~★★★
説明しなきゃならんだろうけど、しづらい。
タイトルに関しては、
ビル名や階数が登録されてなかった場合に
(F)**会議室
みたいに、何が(F)なのかわからなくなっちゃうので、
削るロジックを書いてます。
サブタイトルは、
24時間以内に予定がなかったら「予定はありません」てだけ表示させて、
予定がある場合は複数件の予定があった場合でも
最初の一件分だけ、
予約者の名前か件名の後に改行して開始終了時刻を表示させる
みたいな感じ
を、文字数とか区切り文字で無理くり抽出してるんですね。
本文は、
いらなかった。
ゴメン。
するとこんな具合になったかな?
いいねぇ。
そうそう。
なんか出来上がりつつある感じ出てきたねぇ。
じゃあ、このページ最後。
★★★~
ギャラリー内の > ボタンに以下の文字列を書いてね
== > ボタンのOnSelect ==
Select(Parent);
ClearCollect( DataDetailSplit , Split(MessageTrim.Text,"`").Result);
Set( RoomNameString , RoomNameAtView.Text );
ForAll(DataDetailSplit , Text(Left(Mid(MessageTrim.Text,Find("$$",MessageTrim.Text)+2),Len(MessageTrim.Text)-SubjectTrimNo-2)));
Remove( DataDetailSplit , Last(DataDetailSplit.Result) );
Set(MessageNULL , If(MessageCollect.Text="予定はありません",MessageCollect.Text,"MMM"));
Navigate(DetailScreen)
====
~★★★
24時間以内のスケジュールを全件取得したんだけど、
一覧画面には表示できないしゴチャつくから表示させたくないので、
非表示で隠し持っておいた値を DataDetailSplit ってコレクションに
値をぶちこむ感じとか、会議室名を RoomNameString って変数にぶちこむ感じ
を、このボタンで、やってます。
じゃあ、次行こうか。
3-3.詳細画面に表示するデータの実装
さて。
この画面に関してはもう直感で出来るかもね。
今はまだ何のデータ紐づけもしていないギャラリーが
ポツンとあるだけだよね。
じゃあ、せっかくだから開いた会議室の、会議室名の表示用に
★★★~
画面左上あたりに、君のセンスでラベルを一個追加しよう。
ラベルの Text には RoomNameString と指定してあげてください。
そんで、ギャラリーのデータソースには DataDetailSplit を選択してあげよう
~★★★
★★★~
よし、じゃ次は新たにギャラリー内にラベルを追加して、
RoomDetailText って名前を付けよう。
中身(Text の値)は以下。
ThisItem.Result
で、次は既存の二つのラベル。
タイトルと予約済みの時間を表示しよう。
先ずは上下のラベルに名前を付けてあげよう。
上:Title
下:StartEndTime
楽勝だよね。
そしたら次はTitleの中身。
以下の文字列を記入しよう。
== Title の中身 ==
If(MessageNULL <> "予定はありません",
If(Left(RoomDetailTEXT.Text, Find("$$",RoomDetailTEXT.Text)-1)="","予定はありません",
Left(RoomDetailTEXT.Text, Find("$$",RoomDetailTEXT.Text)-1)),
"予定はありません")
====
== StartEndTime の中身 ==
Mid(RoomDetailTEXT.Text, Find(";",RoomDetailTEXT.Text)+1)
====
~★★★
タイトルは、予約者の名前か件名。
StartEndTimeは、開始終了時刻。
そしたら一旦こんな感じになるかな?
よーっし!
これでほぼ実装完了!
おめでたふ!
※もし何か書き忘れてたらすんません。
ちな、最後にギャラリーの > は要らないから、
非表示にしちゃおうね。
Visible を false にするんだよ。
もしくは右側のプロパティから「表示」をオフにしてあげるのね。
じゃあ、想定される動きを画面で見てみよう。
まず最初のPowerAppsを開いたページから。
「会議室一覧」ボタンを押すと・・・
ちょっとばかし時間かかるね。
でも我慢の子。
っどーん
できたねぇー。
んで、予定がある会議室の > マークをクリックすると・・・
いやー、おめでとう!
本当におめでとう!
これでもう君も立派なダンジョンマスターだよ。
だ が
しかし!
昨今のシステムっつーのはUI(見た目)がかなり重要視されるのである。
シンプルでいいけど、ユーザーにもワクワク感が欲しいものです。
というわけで、デコレーションタイムへ突入したいと思います。
4.PowerAppsの画面をデコる
本当のボーナスステージだね。
好き勝手自由にやってもらってかまわない。
ただ、その「自由なやり方」がわからない方向けに
こんな感じに出来ちゃうよ!
という、アキヒササンタからのプレゼントだよ!
アキヒサンタだよ!
てへ
ここから先は、 ★★★ をつけないから、
自由にやりたいとこだけ抽出してね!
また、ここから先出てくる動画は、
以下のURLリンク先からGETさせていただきました!
https://pixabay.com/ja/videos/
4-1.ホーム画面にロゴをバーン
もう僕はお見せしたけど、HomeScreenにロゴ背景をセットしたよ。
やり方は、以前のブログにも書いてあるけど、
こんな感じね。
まずはHomeScreenの編集画面で、
「画像」の追加をしよう。
すると、こんなちいちゃなものが表示されるから、
画面右側のプロパティの 画像 のところで「+画像ファイルの追加」を押す。
すると見慣れたファイル選択ダイアログが開くから、
好きな画像を選択してくれればいい。
選んだら、あとはもう言わなくてもわかるね?
ちいちゃい状態じゃ意味ないから、画面いっぱいに拡大してあげればよし。
画面いっぱいまで拡大したら、
先に配置したボタンが消えちゃってるね。
画面左のツリービューからボタンを選択して、
一番手前に表示してあげましょう。
もしくは、背景画像を最背面にしてあげる。
最背面にしてあげた方がいいかな。「背景」っていうくらいだし。
はい、見事HomeScreenの完成。
簡単しょ?
次行こ次。
4-2.一覧画面に動画をズドン
会議室の一覧画面だね。
今はきっとこんな感じかな。
すっごい味気ないので、気合入れてデコりましょう。
気合入れるっつっても、やることは簡単。
PowerAppsちゃんは、動画を背景に設定することもできるんだ。
じゃ、やってみよう。
まずは、メディアの中から「ビデオ」を選択。
すると、こんな感じのヤツが表示されるね!
そしたら、あとはもうさっきと同じだね!
さっきと同じくファイル選択ダイアログが表示されるから、
動画ファイルを選択するとこんな感じになるから、
例によってマックスまで広げちゃおう。
ヘッダー部分を残したければ、ヘッダー部分を含まないことも出来るし。
広げたはいいものの、まず真ん中に再生ボタンとか、
下に時間表示のアレが表示されてるね。
邪魔だよね。
邪魔なやつは消してやりましょう。
オレ、邪魔なヤツ、消ス。
すいません。
ちょっと僕の中に眠る封印されし邪鬼が出てきそうになりました。
失礼しました。
じゃア、邪魔ナヤツ、消シ方、オシエル。
マズ、右ノプロパティ、見ル・・・
コントロール、オフ・・・
危ない危ない。
また意識が乗っ取られるところでした。
助かりました。
助けてくれてありがとう。
お礼といっちゃあ何だが、
アナタが可愛い女子だった場合、
僕とお付き合い・・・
あいやなんでもないです。
で、だ。
要らない表示を消せたのは良いんだけど、
この状態だとまだ動画再生されないのね。
で、さっきのプロパティ見た時に
気付いた方もいらっしゃるかもしれないんだけど
あのプロパティをいじりましょう。
「自動開始」と「ループ」をそれぞれONにしましょう。
そしたら動画か開始し始めたかな?
みなさんがどんなステキな動画をセットしたかわからないが、
僕はこんな感じのものをセットしてみました。
取得先↓
https://pixabay.com/ja/videos/%E3%82%AF%E3%83%AA%E3%82%B9%E3%83%9E%E3%82%B9-%E3%83%84%E3%83%AA%E3%83%BC-%E3%82%AF%E3%83%AA%E3%82%B9%E3%83%9E%E3%82%B9-54032/
で、さっきと同じくこの動画を最背面に配置する。
・・・と?
うん。
そうだね。
文字が見えないよね。
だから、各パーツの文字を白とかにしてみましょうか。
んで、詳細画面に移動する > のアイコンもちょっとシャレオツに
〇付のアイコンに変更してみました。
どうでしょう。
私はセパレーターの色を緑色にして、
列の境目に緑色の縦線も追加してみました。
あれ?
こうなってくると、ヘッダーの部分まだ未着手ですね。
テコ入れしましょう。
まずはテキストを変更して、フォントサイズも40くらいにしましょう。
次に色もセパレーターの色にあわせて変更して、
現在の時刻が表示されてたら親切だと思うので、
時計アイコンを追加しましょう。
時計アイコンを左上に配置して、
時刻を表示するためのラベルも追加しましょう。
現在の時刻を表示するためには、タイマーってやつが必要です。
このDurationの値を 1000 に変更します。
右側プロパティからでも変えれるよ!「期間」って項目の値だね!
続けて、このタイマーの OnTimerEnd を以下の文字列に変更します。
Set( CurrentTime , Now())
次に、このタイマーのプロパティを変更しましょう。
そしたら最後の仕上げ。
さっき追加しておいたラベルの Text の値に以下の文字列を指定して、
タイマー君は非表示にしちゃいましょう。
Text( CurrentTime, "[$-ja]yyyy年mm月dd日 hh時mm分ss秒" )
んでついでにラベルも文字も大きくして、
時計アイコンとラベルの文字の色を白くすれば完成!
時刻の文字のフォントサイズもうちょっとでかくてよかったかも。
↑は20。23くらいには出来るかな。
さて。どうよ。
ここで一回全体がどんな感じになってるか見てみよう。
っででーん
そしたら、個人的には更新ボタンが欲しいので、
ヘッダーの右側に更新ボタンを配置してみました。
更新ボタンのOnSelectには、
HomeScreenに配置したボタンのOnSelectの値を
コピペして貼っちゃえばいいのでね。
えいっ!
ゴイスーじゃない?
女子高生ばりにデコれたんじゃない?
まじくりすますじゃない?
4-3.詳細画面に動画とか画像とかをドシャーン
じゃ、最後ね。
あーしにまかせとけば、まじ大丈夫だから。
オニなうい感じにキメてやっから。
次のページはもう超らくしょーだかんね。
むしろ、ここまで来た道程を振り返れば
自力でできるんじゃね?
僕のチョイス動画↓
https://pixabay.com/ja/videos/%E9%9B%AA%E7%89%87-%E9%9B%AA-%E3%82%AF%E3%83%AA%E3%82%B9%E3%83%9E%E3%82%B9%E3%83%95%E3%83%AC%E3%83%BC%E3%82%AF-57520/
チョーヤバいんだけど。
と、いうことでね。
一連の流れに沿って見てみるとこんな感じに仕上がりました。
終 わ り だ YO!
実際、色々
「文字列を何文字目から何文字目までを切り取り」とか
「#とか`(バックコーテーション)とかを区切り文字にしてつなげて
あとでSplitして・・・」
みたいな、だいぶコーディング的には不細工なので、
これが一番正しいコーディング・・・
では絶対ないので、その点は御覚悟くださいね。
~~~ 本 題 終 了 ~~~
あー。
疲れましたね。
どうだい?
本当にでかかっただろう?
アキヒサンタからのクリスマスプレゼントは。
コレを本当に最初から最後まで読んでくれた方に聞きたい。
読むのに何日かかりました?
僕はこの記事書き始めてから完了するまで、
10000時間くらい使いました。
もう、明日朝目覚めたら、
灰になっててもおかしくないくらい。
朝目覚めたら
どっかの誰かに
なってやしないかな
なれやしないよな
できればミスチルの桜井さんになりたい。
では。
今日は本当にお疲れ様だったね。
お家帰ってゆっくりしてね。
今回の記事は
以下の皆様方のブログを参考にさせていただきました!
むしろ、それ見た方が早い。
今知ったんだけどこの記事、約3万文字あるわ。
調子に乗って、この記事は
「Office 365 Advent Calendar 2020」
に参加しちゃいました。
2020/12/11(金)分のエントリーです。
とは言いつつ
「そぐわない。消せ。」
と言われたら即時にエントリーから撤退します!