コルネの進捗や備忘録が記されたなにか

進捗や成果物や備忘録てきななにかを雑に更新していきます。

Power Apps のコンポーネントでコレクションの情報を渡す

はじめに

7/31(土)にこちらの勉強会で登壇させていただきました。

powerapps.connpass.com

前々からやりたいって言っていたイベントを開催できたので私は満足です。
登壇を引き受けてくださった、Akira さん、Hiro さん、司会をしてくださったやまさん、ありがとうございました!!!!

この勉強会の内容はAkira さんがこちらのブログで纏めてくれていますので、参加されてない方はこちらで他の方の登壇内容もチェックしてみてください。

hanakuso365.hatenablog.com

また、Connpass のページにて資料も公開されていますので、興味を持たれた方は是非ご一読ください。

私の登壇資料はこちらです。

www.slideshare.net

また、当日の私の登壇の様子は私のYouTube のchannel にアップしていますので、合わせて確認していただけますと幸いです。

youtu.be

もしよろしければ、チェンネル登録、高評価、Twitter のフォローなどよろしくお願いします!(テンプレート)

さて、前置きはここまでにして、私はこの勉強会のなかでコンポーネントでレコードやテーブルを扱う際には作成時に宣言したフィールドとは異なるフィールドが設定されたれこーどやテーブルは渡すことができない。と説明しました。

こちらの内容に間違いはないのですが、"情報"であれば渡すことが可能です。

この記事ではその方法を紹介したいと思います。

ただはじめに断っておくと、これはあくまで"こうすればできないこともないよ"という内容ですので、実際利用する際は

  • 本当にフィールド不定形の情報を扱う必要性があるのか
  • そのコンポーネントを今後運用できるのか

ということを考慮したうえで、利用を行ってください。

コンポーネントにコレクションの情報を渡す

ロジック

勉強会でも説明した通り、コンポーネント作成時に宣言したフィールドと異なるフィールドが設定されたレコード/テーブルをコンポーネントに渡すことはできません。
ではどうするかというと、コレクションをJSON 化してコンポーネントに渡します。

JSON 形式に変換されたコレクションはテキスト型として扱うことが可能ですので、コンポーネント側はテキストデータを受け取ることになります。

このやり方はPower Apps からPower Automate にコレクション情報を渡した経験がある方であれば馴染の深いやりかたかもしれません。

Power Apps で実装する

まずコンポーネントには、JSON フォーマットに変換されたコレクション情報を受け取るためのプロパティ or パラメータを用意します。

今回は入力プロパティを用意します。

f:id:koruneko:20210809145458p:plain

このプロパティには、以下のようにして変換した値を渡す必要があります。

Set(
    JsonCol, 
    JSON(
        Table(
            {SampleStringField: "SampleText1", SampleNumberField: 10, SampleBooleanField: true},
            {SampleStringField: "SampleText2", SampleNumberField: 100, SampleBooleanField: false}
        ), 
        JSONFormat.IndentFour
    )
)

上の式では、Table 関数で定義されたテーブル情報をJSON 関数JSON 化しています。

変換されたテキスト値が JsonCol に設定されるので、コンポーネントには JsonCol を渡してあげればよいです。

これで、コンポーネントにコレクション情報を渡すことができるようにはなったわけですが、残念なことにPower Apps でJSON データを解析するような関数は用意されておりません。

なので、自力でJSON データを解析して、key とvalue を得る必要があります。

項目の名前を抜き出す

先ほどの式を実行すると、 JsonCol には以下のようなJSON データが設定されます。

JsonCol

[
    {
        "SampleBooleanField": true,
        "SampleNumberField": 10,
        "SampleStringField": "SampleText1"
    },
    {
        "SampleBooleanField": false,
        "SampleNumberField": 100,
        "SampleStringField": "SampleText2"
    }
]

今は項目の名前を取り出したいので、上記でいうと SampleStringField, SampleNumberField, SampleBooleanField になります。

これらを取り出すためには、正規表現を用いたいと思います。

正規表現を用いてテキストの抽出を多なうので、MatchAll 関数を利用します。

項目の名前は "": で囲まれた値ですので、これを正規表現で表したいと思います。

上記を踏まえて式を記載すると以下のようになります。

MatchAll(Self.JSONFormatCollection, "(?<="").*?(?="":)")

第一引数が、JSON データで第二引数が項目の値を取り出すための正規表現となっています。

正規表現???という方も多いと思いますので、簡単に解説します。

(?<=[パターン])

これで"肯定後読み"と呼ばれる表現方法になります。
肯定後読みでは、[パターン]にマッチした場合にその部分の文字列の末尾位置にマッチすることになります。

今回 "" としているので " の次の文字の位置にマッチすることになります。

.*?

これは"最短マッチ"と呼ばれる表現方法です。
この表現の直前のパターンに対応する直後に記載されたパターンまでを最短でマッチさせるための表現になります。

これは実際の動きを試してもらうと早いと思います。
下記サイトで <.*><.*?> の2パターンの正規表現<ABC><DEF> をチェックしてみてください。

www.softel.co.jp

(?<=[パターン])

これで"肯定先読み"と呼ばれる表現方法になります。
肯定後読みとは異なり、[パターン]にマッチした場合にその部分の文字列の先頭位置にマッチすることになります。

今回 "": としているので、 ": の前の文字の位置にマッチすることになります。

Power Apps の式に戻ります。

この記載方法ですと、複数レコード存在するとレコード数分項目名がとられてしまいます。
項目名は重複していないはずであるので、Distinct 関数で重複を削除してあげましょう。

Distinct(MatchAll(Self.JSONFormatCollection, "(?<="").*?(?="":)"), FullMatch)

これにより、JSON データからkey 項目、コレクションの項目名を取得することができました。

項目の値を取り出す

最後に項目の値を取り出そうと思います。

項目の値は ":\r\n|\n (改行を表しています。)で囲まれている値を取得すれば、取得できそうです。
ただし、テキストデータは " で囲まれており、データは , で区切られているのでこれらを除去する必要があります。

これらを踏まえて式に表すと、以下のようになります。

With(
    {colVal: Distinct(MatchAll(Parent.JSONFormatCollection, "(?<="": ).*?(?=(\r\n|\n))"), FullMatch)},
    ForAll(
        Sequence(CountRows(colVal)),
        {
            Id: ThisRecord.Value,
            Value: Substitute(Substitute(Last(FirstN(colVal, ThisRecord.Value)).Result, """", ""), ",", "")
        }
    )
)

" と ',' の除去にはSubstitute 関数を利用しています。

これにより項目の値を抜き出すこと自体は成功するのですが、値がただ列挙されたテーブルを取得できるだけで、項目の名前との紐づけが行えません。

これらを紐づける解決策の1つとして、名前と値をそれぞれ紐づけるためのID をもたせてあげればよいです。

名前にID を順に振り、値はID 値を名前の数で割ったあまりで紐づければいいというわけです。

ここの詳しい実装方法と解説は以下コンポーネントの解説で行おうと思いますので、少しお待ちください。

この記事では式だけ記載しておきます。
わかる人はここから読み取ってください(という無茶ぶりです)。

項目の名前にID を割り振る。

ForAll(
    Sequence(CountRows(Parent.ColumnNames)),
    {
        Id: ThisRecord.Value,
        Result: Last(FirstN(Parent.ColumnNames, ThisRecord.Value)).Result
    }
)

選択した項目の名前と、項目の値を紐づける。

With(
    {
        colAllVal:
        With(
            {colVal: Distinct(MatchAll(Parent.JSONFormatCollection, "(?<="": ).*?(?=(\r\n|\n))"), FullMatch)},
            ForAll(
                Sequence(CountRows(colVal)),
                {
                    Id: ThisRecord.Value,
                    Value: Substitute(Substitute(Last(FirstN(colVal, ThisRecord.Value)).Result, """", ""), ",", "")
                }
            )
        )
    },
    With(
        {ColumnNameGalleryAllItems: CustomDataTableComponent_ColumnNameSelectGallery.AllItems},
        ForAll(
            Sequence(CountIf(ColumnNameGalleryAllItems, CustomDataTableComponent_ColumnNameCheckBox.Value = true)) As CheckCount,
            With(
                {checkItem: Last(FirstN(Filter(ColumnNameGalleryAllItems, CustomDataTableComponent_ColumnNameCheckBox.Value = true), CheckCount.Value))},
                {
                    key: checkItem.Result,
                    val: Filter(colAllVal, Mod(Id, CountRows(Parent.ColumnNames)) = Mod(checkItem.Id, CountRows(Parent.ColumnNames)))
                }
            )
        )
    )
)

これで入れ子になったテーブルが取得できるので、ギャラリーの中にギャラリーやリストを設定してあげればよいです。

おわりに

最後説明が放り投げた状態で終わらせてしまいましたが、ちょっとここの説明までいれてしまうと長くなってしまいそうですので、次回に回させてください。

記事の途中で説明した正規表現はPower Apps 以外でも覚えておくと大変便利なパターンマッチ方法ですので、気になった方は是非この機会に勉強してみてください。

Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その3~

はじめに

この記事はPower Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その2~の続きです。

Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その1~
Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その2~

参考文献

Power Apps Easiest Way To Upload Files To A SharePoint Document Library

Power AppsからExcelファイルを取り込んでDataverse for Teamsにデータ登録 - MoreBeerMorePower

Power Appsにおける画像の扱いについて - Qiita

Power Apps からアップロードされたファイルをSharePoint ドキュメントライブラリに保存する

Power Apps V2 トリガーを利用

次はPower Automate にてPower Apps V2 トリガーを利用してSharePoint ドキュメントライブラリにファイルをアップロードするやり方です。

f:id:koruneko:20210708000012p:plain

Power Automate 側の処理

今回はPower Automate 側のフローから作成していきます。

トリガーとして利用するのは、"Power Apps (V2)" です。

f:id:koruneko:20210708000437p:plain

こちらのPower Apps V2 では、Power Apps からPower Automate に渡すデータの定義が可能になりました。

f:id:koruneko:20210708002403p:plain

選択可能なのは

  • テキスト(Text)
  • はい/いいえ(Boolean)
  • ファイル(File)
  • 電子メール(Email)
  • 数(Number)
  • 日付(Date)

の6つです。

これらの変数は、自分で名前を付けることができるため、用途に合わせてわかりやすい名前をつけたり、対象の変数を必須 or オプションにすることが可能です。

また、例えばテキストですと複数選択リストにしたり、ドロップダウンリストにしたりすることもできます。

ここの詳しい纏めはまた別の機会にすることにします。

今回はファイルを扱いますので、ユーザー入力の種類では"ファイル"を選択します。

変数名や説明はなんでもいいですが、対象の変数を必須にしたのか?オプションにしたのか?だけは最低限把握しておいてください。

ここで必須にしたのかオプションにしたのかでPower Apps からPower Automate への値の渡し方が変わってきます。

あとは、これまでと同じようにファイルの作成アクションを追加して、任意のフォルダーパスを選択します。

ファイル名には

@{triggerBody()['file']['name']}

を設定してください。

ファイルコンテンツには

@{triggerBody()['file']['contentBytes']}

を設定してください。

これでフローの作成は完了です。

f:id:koruneko:20210708013608p:plain

Power Apps 側の処理

Power Apps 側で必要なコントロールは、

の2つだけです。

前回はPower Apps からPower Automate にファイルを渡すために色々やっていましたが、今回はその必要はありません。
ファイル名とファイルコンテンツを渡すだけです。
形式はレコードになります。

ただし先ほども記載したように1点注意が必要で、Power Automate で宣言した変数が必須化オプションかで渡し方が変わってきます。

それぞれを設定した場合の設定例を記載します。

必須の場合

PowerAppsV2_Create_DocumentFile_to_SharePointCreate_DocumentFile_to_SharePoint_Required.Run(
    {
        name: First(AttachmentComponent_2.Attachments).Name,
        contentBytes: First(AttachmentComponent_2.Attachments).Value
    }
)

オプションの場合

PowerAppsV2_Create_DocumentFile_to_SharePointCreate_DocumentFile_to_SharePoint.Run(
    {
        file:{
            name: First(AttachmentComponent_2.Attachments).Name,
            contentBytes: First(AttachmentComponent_2.Attachments).Value
        }
    }
)

オプションの場合は、必須と違い省略してもいい項目となっています。
そして例えばテキストのオプション変数もあった場合、順不同で設定してもよいです。

このときPower Apps から変数を受け取ったPower Automate がその値がなんの値かを判断する必要があります。
その判断部分が {file:} となります。

このオプションの設定方法として、皆さんに馴染み深そうなのは SearchUser でしょうか。

f:id:koruneko:20210708015916p:plain

これもオプション項目が設定でき、これらのオプション項目を設定せずとも関数を実行することができますね。

以上でPower Apps V2 トリガーを利用したSharePoint ドキュメントライブラリへのファイルのアップロード処理は作成完了です。

それぞれのメリット/デメリット

最後にそれぞれのメリット / デメリットについて纏めます。

  • 方法1
    SharePoint リストを経由してドキュメントライブラリに保存
  • 方法2
    Power Apps にアップロードされたファイルのコンテンツ情報をdatauri に変換してPower Automate に渡しドキュメントライブラリにファイルを保存
  • 方法3
    Power Automate のPower Apps V2 トリガーを利用
方法 メリット デメリット
方法1 ・3つの中で一番単純
・複数ファイルをアップできる
・本来不要なSharePoint リストを作成/管理する必要がある
・即時実行でない
方法2 ・即時実行が可能
・複数ファイルをアップできる
・ロジックがちょっと複雑
方法3 ・即時実行が可能 ・複数ファイルをアップするときはそれだけフローで変数の定義が必要

おわりに

あくまで個人的な意見ですが、用途に合わせて方法2 or 方法3を利用するのがいいんじゃないかな。
と考えます。

方法1を利用するパターンはSharePoint リストにもアップする必要があって即時アップじゃなくても許容できる場合ですかね。
管理対象が増えるのは保守的な観点から考えてよくないと考えます。

自身の用途に合ったものを取捨選択するのが大切ですね。

Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その2~

はじめに

この記事はPower Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その1~の続きです。

Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その1~
Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その3~

参考文献

Power Apps Easiest Way To Upload Files To A SharePoint Document Library

Power AppsからExcelファイルを取り込んでDataverse for Teamsにデータ登録 - MoreBeerMorePower

Power Appsにおける画像の扱いについて - Qiita

Power Apps からアップロードされたファイルをSharePoint ドキュメントライブラリに保存する

ファイルのコンテンツ情報をdatauri に変換してドキュメントライブラリに保存

続いての方法は慣れていない人にとってはちょっと難しいかもです。

処理としては以下のようになります。

  1. 添付ファイルコンテンツをdatauri に変換
  2. 1で取得したdatauri 形式でPower Automate にファイルコンテンツを渡す
  3. Power Apps から受け取ったファイルコンテンツ(datauri)をbinary に変換
  4. ファイルをSharePoint ドキュメントライブラリに作成

1~2がPower Apps で3~4がPower Automate の処理になります。

Power Apps 側の処理

まずはPower App に添付ファイルコントロールを配置します。
前回紹介したように、コンポーネントを利用すると便利ですので是非お試しを。

さて、この添付ファイルコントロールからアップロードされたファイルですが、どこに保存されるか皆さんご存じでしょうか?

実際にファイルコントロールからファイルをアップロードして、アップロードされたファイルのValue をみてみましょう。

f:id:koruneko:20210707002525p:plain

appres://blobmanager/XXXX/1

となっています。
これはPower Apps のコントロールから読み取ったファイルが保存される場所となっています。

データの種類 - Power Apps | Microsoft Docs

このときの形式はURI テキスト文字列となります。

この結果をPower Automate に渡しても(Power Apps で特に何もせず扱おうとしても)テキストなのでファイルを想定通りに作成してくれることはありません。

このURI テキスト文字列をdatauri 形式に変換するためには、画像コントロールを利用してあげる必要があります。

Power Apps の画像コントロールURI テキストを読み込むと初めてBinary としてデータを読み込んでくれます。

ここまできて初めてファイルコンテンツをdatauri に変換するための準備ができました。

この画像コントロールのデータ( Image1.Image ) をラベルなどで表示させてもまだ先ほどと出力結果は変わりません。

ではどうするのかというとJSON 関数を用います。
JSON 関数にBinary データを渡し、フォーマットに IncludeBinaryData を指定することでdatauri 形式の結果を取得することができます。

1点注意として、このJSON 関数は非動作関数ですので、ラベルなどのコントロールでは設定することができません。
一度変数などに格納してあげてください。

最後に、このJSON 関数の戻り値は文字列ですので、ダブルクォーテーション(")が付与されています。

このままPower Automate に渡してしまうと文字列として扱われてしまうので除去します。

Substitue 関数を用いてダブルクォーテーションを置換しましょう。

Substitute(JSON(Image1.Image, IncludeBinaryData), """", "")

さて、これで1の処理が実現できるわけですが、今回はもう少し先をいって複数ファイルを処理できるようにしましょう。

上で添付ファイルコントロールからアップしたファイルがどこに保存されるのかを確認するために、First 関数を利用していましたが、これは添付ファイルコントロールが複数のファイルを受けとる性質上テーブル形式となっているため、First 関数を使って1レコード取得していたのです。

当然ですが、1つの画像コントロールに複数のファイルコンテンツを設定することはできません。
よって、添付ファイルの数だけ画像コントロールが必要になってきます。

コントロールを添付ファイルの数だけ(レコードの数だけ)増やす。
となると、ギャラリーコントロールを使えばいいですね。

ギャラリーを配置し、その中に画像コントロールを追加します。
設定値はそれぞれ以下のようになります。

Gallery1.Items

AttachmentComponent_1.Attachments

Image1.Image

ThisItem.Value

先ほど説明したようにJSON 関数は非動作関数なので、次の処理でdatauri に変換します。

ボタンを配置し、 OnSelect に以下処理を記載します。

Button1.OnSelect

Set(
    attachmentFiles,
    ForAll(
        Gallery1.AllItems,
        {
            name:Name,
            content:Substitute(JSON(Image1.Image, IncludeBinaryData), """", "")
        }
    )
);

datauri に変換する処理は、ギャラリーのアイテム数分行いたいので、ForAll 関数を用いています。

ForAll の結果はテーブルを返しますので、各レコードには名前(name)とdatauri 変換されたファイルコンテンツ(content)が含まれるようにしています。

このテーブルのままではPower Automate に渡すことができないので、テキスト形式にします。

この際に使用するのもJSON 関数です。

JSON(attachmentFiles, IndentFour)

とすることで、テーブル(コレクション)をJSON 形式に変換することが可能です。
これはよく使うので覚えておくと便利です。

実際のPower Automate に渡す処理は以下です。

Button1.OnSelect

Create_DocumentFile_to_SharePoint.Run(JSON(attachmentFiles, IndentFour))

Power Automate 側の処理

Power Automate の全体フローは以下のようになっています。

f:id:koruneko:20210707013222p:plain

まず、Power Apps からはJSON 形式でデータが渡ってきているので、その中の情報を抜き出します。

"JSON の解析"アクションを追加し、以下のように設定します。

f:id:koruneko:20210707013537p:plain

スキーマ

{
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "content": {
                "type": "string"
            },
            "name": {
                "type": "string"
            }
        },
        "required": [
            "content",
            "name"
        ]
    }
}

これで、先ほどForAll で作成したようなテーブルの情報がこのフロー内でも扱えるようになりました。

続いて"ファイルの作成"アクションを追加します。

ファイル名にはJSON の解析で取得した name ( @{items('Apply_to_each')['name']} ) を設定します。
name には添付ファイルのファイル名を設定するように先ほどレコードを作成しましたね。

続いてファイルコンテンツに設定する式ですが、Power Apps から渡したdatauri 形式のまま設定してもファイルが想定通り作成されません。
ここに設定するのは、Binary 形式です。

そこで、dataUriToBinaryという関数を利用します。
これを利用することでdatauri 形式を Binary 形式に変換することが可能になります。

dataUriToBinary(items('Apply_to_each')['content'])

以上でファイルのコンテンツ情報をdatauri に変換してドキュメントライブラリに保存する方法の纏めは完了です。

おわりに

実際に処理を作成するときに、考えそうなやり方にそって記事を作成しましたが、大分冗長てきな書き方になってしまいました。。。
長くなってしまいましたが、最後まで読んで頂きありがとうございましたー

次はPower Apps V2 コネクタを利用したやり方の紹介になります。

Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その1~

はじめに

今回はPower Apps でローカルからアップロードしたファイルをSharePoint のドキュメントライブラリに保存する方法を3パターン纏めたいと思います。

Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その2~
Power Apps でローカルからアップしたファイルをSharePoint のドキュメントライブラリに保存する ~その3~

参考文献

Power Apps Easiest Way To Upload Files To A SharePoint Document Library

Power AppsからExcelファイルを取り込んでDataverse for Teamsにデータ登録 - MoreBeerMorePower

Power Appsにおける画像の扱いについて - Qiita

各やり方の特徴

1つ目

まず1つ目はSharePoint リストを経由してドキュメントライブラリに保存する。という方法です。
多分このやり方が理論的には一番簡単です。

メリデメは各やり方を記載したあとに纏めますが、本来不要なSharePoint リストを用意してあげなきゃいけないです。

2つ目

2つ目のやり方は、Power Apps にアップロードされたファイルのコンテンツ情報をdatauri に変換してPower Automate に渡し、ドキュメントライブラリにファイルを保存する。という方法です。

これは、Power Apps でのファイルの扱いについて理解しているかどうか?で理解度が変わってくるかと思います。

3つ目

3つ目のやり方は、Power Automate のPower Apps V2 トリガーを利用する。という方法です。
Power Apps V2 トリガーを利用することにより、トリガー内でデータ定義を行えるようになりました。

恐らく今後Power Apps とPower Automate 間でのファイルの受け渡しといえばこの方法が主流になってくるんじゃないかな?とか個人的には考えています。
ただし後述しますが、このやり方では実現できないこともあります。

Power Apps からアップロードされたファイルをSharePoint ドキュメントライブラリに保存する

Power Apps でローカルからファイルをアップロードするためには、添付ファイルコントロールが必要です。

ただしこれを利用するためには、SharePoint リストなどのデータソースで添付ファイルを含む列を作成し、そのデータソースへの追加 / 編集を行うためのフォームコントロールを配置することで、初めて得られることができます。

f:id:koruneko:20210704200026g:plain

そうして得られたコントロールをフォーム外へコピペし、エラー内容を取り除くことで初めて利用できるコントロールとなっています。

ただ毎回この操作やるのめんどくさいですよね?

なので、このように、コンポーネント化しておくことを推奨します。

f:id:koruneko:20210704200404p:plain

こうすることにより、比較的簡単に添付ファイルコントロールを扱えるようになります。

SharePoint リストを経由してドキュメントライブラリに保存

まずは、ファイルを一時保存するためのSharePoint リストを作成します。
添付ファイルの項目以外はとりあえず今回は不要なので、必須入力を外しておきましょう。

タイトル(Title)項目が必須入力になっていると思いますので、サイトコンテンツより対象リストの設定を開き、タイトルの必須入力を外します。

f:id:koruneko:20210706001623p:plain

Power Apps を開き、データから先ほど追加したSharePoint リストを選択します。

f:id:koruneko:20210706002859p:plain

編集フォーム(フォーム > 編集)を追加し、データソースに先ほどのSharePoint リストを設定します。

添付ファイルコントロールが表示されていなければ、フィールドの編集より添付ファイルを追加します。

ボタンもしくは、Screen の OnVisible

NewForm(Form1)

を追加します。

これで、フォームを新規で登録できるようになりました。

続いてフォームの内容をリストに保存する処理を記載します。
ボタンを追加して OnSelect

SubmitForm(Form1)

を設定します。

これで添付ファイルをSharePoint リストに登録することができました。

次にSharePoint リストにデータが追加されたことをトリガーに動くフローをPower Automate で作成します。

全体のフローはこんな感じです。

f:id:koruneko:20210706004141p:plain

"サイトのアドレス"及び"リスト名"には先ほど作成したリストを選択するように設定します。

"添付ファイルの取得"及び"添付ファイルのコンテンツの取得"アクションの"ID"には"項目が作成されたとき"で取得したIDを用います。

@{triggerOutputs()?['body/ID']}

"添付ファイルのコンテンツの取得"の"ファイル識別子"には"添付ファイルの取得"で取得したファイル識別子を用います。
これを設定すると、Apply to each が追加されます。
添付ファイルの取得では複数項目を返す可能性があるからですね。

@{items('Apply_to_each_2')?['Id']}

"ファイルの作成"の"ファイル名"には"項目が作成されたとき"で取得したDisplayName を使用します。

@{items('Apply_to_each_2')?['DisplayName']}

"ファイルコンテンツ"には"添付ファイルのコンテンツの取得"で取得した添付ファイルのコンテンツを利用します。

@{outputs('添付ファイルのコンテンツの取得')?['body']}

処理の流れを簡単に説明しますと(かいてあるままですが。。。)

  1. ユーザがPower Apps でファイルを読込
  2. 1で読込んだファイルをPower Apps からSharePoint リストへ追加
  3. 2をトリガーにフローが実行
  4. SharePoint リストへ追加されたレコードの添付ファイルを取得
  5. 添付ファイルのファイルコンテンツを取得
  6. 4, 5の内容をもとに指定のSharePoint ドキュメントライブラリへファイルを作成

となっています。

ここまでみながら作成されてみた方の中で、
「実際に試してみたけどフローが動かない!」
という方がおられるかもしれません。

それはPower Automate の制限によるものです。
詳しくは以下公式ドキュメントをご確認ください。

制限と構成 - Power Automate | Microsoft Docs

もしくはPower Automate の画面にて、"Ctrl + Alt + A"を押してプラン情報を参照してみます。

こんな感じのJSON 形式のデータをみることができます。

f:id:koruneko:20210706012719p:plain

これの"maximumRecurrenceFrequency"となっている箇所がトリガーの実行間隔の値になります。
この値の単位は[秒]です。

複数"maximumRecurrenceFrequency"が表示されている場合は、そのユーザに複数のライセンスが割り当てられているということになります。
この場合、最も短い時間が適用されます。

このように、フローはリスト追加後すぐには動かないので、少し待ってから確認をしてみてください。

おわりに

この方法のメリットは以下です。

  • 処理のロジックが簡単
  • 複数ファイルを作成できる

ですが、以下デメリットがあります。

  • 無駄にSharePoint リストを作成する必要がある
  • 処理のタイミングが即時じゃない

次回紹介するファイルのコンテンツ情報をdatauri に変換してドキュメントライブラリに保存する方法は少しロジックが難しいかもしれませんが、複数ファイルを処理でき、また、即時でファイルがSharePoint ドキュメントライブラリに作成することがきます。

Power Apps でコントロールのプロパティは変更せず画面の向きを変更する

はじめに

この記事では、Power Apps のアプリの向きを内部に設定されたコントロールのプロパティを変更することなく、変更する方法を纏めています。 

Power Apps の画面の向きについて

この章は知っている人にとっては今更な話なので、タイトルみてなんとなくわかる方は飛ばしちゃってOKです。

Power Apps はデータソースから画面を自動生成することができる

Power Apps ではデータソースを元に以下の3画面を自動生成することができます。

  • 一覧画面(BrowseScreen1)
  • 詳細画面(DetailScreen1)
  • 編集/新規作成画面(EditScreen1)

Microsoft Dataverse からキャンバス アプリを作成する - Power Apps | Microsoft Docs

便利ですねー

ただ、こちらで生成できるアプリは縦向き(携帯電話レイアウト)しか選べないんですよね。。。

f:id:koruneko:20210702010900p:plain

空のアプリやアプリ テンプレートから作成するアプリですと、縦向き(携帯電話レイアウト)か横向き(タブレット レイアウト)が選択可能です。

f:id:koruneko:20210702011116p:plain

アプリの向きを変更する

一度縦向きレイアウトを選んだ後でも、設定から横向きレイアウトに変更することが可能です。(もちろん逆も可能です。)

ファイル > 設定 > 表示
を選択すると、向きを選択できる画面が表示されます。

f:id:koruneko:20210702011411p:plain

今は縦になっているので横に変更してみます。

横を選択すると、以下のようなポップアップが表示されるので、適用を選択します。

f:id:koruneko:20210702011456p:plain

すると、アプリの画面の向きが横に変わりますが、レイアウトが崩れちゃいます。

Before
f:id:koruneko:20210702011703p:plain

After
f:id:koruneko:20210702011759p:plain

これは、縦 → 横 に変更したことにより、横成分のプロパティ(XWidth)に設定してある式が解除されちゃっているからです。

例えば DetailScreen1LblAppName2 を比較してみましょう。

LblAppName2.X

- IconBackarrow1.X + IconBackarrow1.Width
+ 0

LblAppName2.Width

- Parent.Width - Self.X - IconDelete1.Width - IconEdit1.Width
+ 640
  • が変更前で + が変更後です。

この方法で向きを変更してしまうと、このようにレイアウトが崩れてしまうので、向きを変更前のアプリをバックアップかなにかで取っておいて、変更後、差分をもとに戻してあげる必要があります。

一応補足しておきますと、式が解除されちゃうのは、定数(10や200など)を入力しているような箇所ではなく、式(Parent.Width など)でアプリの幅、高さを参照しているようなところです。

アプリ内のコントロールを変えることなく画面の向きを変更する

さて、本題です。
上記のやり方で画面の向き変更できますが、せっかく設定した式解除されちゃうのでレイアウトが崩れてしまい、また設定し直す羽目になってしまいます。

これを回避するために、コード(YAML)を修正することでアプリの向きを変更しようと思います。

前提条件

Power Apps でキャンバスアプリのコード管理を行うために事前準備が必要です。

memo.tyoshida.me

吉田さんの記事で紹介されているような準備が必要です。

  1. .NET Core SDK v3.1.x (x64) をインストールします
  2. GitHub - microsoft/PowerApps-Language-Tooling: Tooling support for PowerApps language and .msapp filesをローカルにコピーします (リポジトリをクローンする - GitHub Docs)
  3. 2でコピーしたディレクトリに移動して build.cmd を実行します
  4. 3が成功すれば bin\Debug\PASopa ディレクトリが作成されるはずです

Power Apps のアプリをローカルに保存する

Power Apps のアプリ(.msapp)をローカルにダウンロードします。

ファイル > 名前を付けて保存 > このコンピュータ > ダウンロード

を選択してアプリ(.msapp)をローカルにダウンロードします。

[アプリ名].msapp

という名前のアプリがダウンロードされます。

アプリを展開する

先ほどダウンロードしたアプリを任意の場所に移動します。

PowerShell(or コマンドプロンプト)を開き、以下コマンドでアプリを展開します。
展開したファイルは[アプリ名].msapp ファイルがあった場所と同じディレクトリに"[アプリ名]_src"というフォルダ名でで展開されます。

[事前準備でダウンロードしてきたディレクトリ]\PowerApps-Language-Tooling\bin\Debug\PASopa\PASopa.exe -unpack [.msappのあるディレクトリ]\[アプリ名].msapp

D:\microsoft\PowerApps-Language-Tooling\bin\Debug\PASopa\PASopa.exe -unpack D:\アプリ.msapp

展開したファイルにはYAMLJSON が含まれています。
お好きなエディターで開いてください。

設定を変更する

先ほど展開されたフォルダを開き、直下にある CanvasManifest.json を開きます。

変更するのは DocumentLayoutHeightDocumentLayoutOrientation DocumentLayoutWidth です。

画面を横向きにする場合は以下のように設定します。

    "DocumentLayoutHeight": 640,
...
    "DocumentLayoutOrientation": "landscape",
...
    "DocumentLayoutWidth": 1136,

画面を縦向きに変更するには以下のように変更します。

    "DocumentLayoutHeight": 1136,
...
    "DocumentLayoutOrientation": "portrait",
...
    "DocumentLayoutWidth": 640,

DocumentLayoutHeigh :画面の高さ
DocumentLayoutWidth:画面の幅
DocumentLayoutOrientation:画面の向き

をそれぞれ表しています。
向きは英語表記の設定値です。

変更したら、ファイルを保存します。

変更した内容をPower Apps でアプリとして読み込む

変更が完了したら、その内容でPower Apps でアプリとして読み込ませます。

このままでは、Power Apps で読み込めないのでまずは.msapp に戻します。

[事前準備でダウンロードしてきたディレクトリ]\PowerApps-Language-Tooling\bin\Debug\PASopa\PASopa.exe -pack [.msappを出力したいディレクトリ]\[アプリ名].msapp D:\[アプリ名]_src

D:\microsoft\PowerApps-Language-Tooling\bin\Debug\PASopa\PASopa.exe -pack D:\EditApp.msapp D:\アプリ_src

2つ目の引数で指定した場所に指定した名前で.msapp ファイルが生成されます。

このファイルをPower Apps で読み込みます。

新しいアプリ > キャンバス > 開く > 参照
より、先ほど作成して.msapp ファイルを選択します。

f:id:koruneko:20210702020857p:plain

するとアプリが表示されますので、エラーなどが出ていないことを確認して保存してください。

ここでなにもせず閉じちゃうとクラウド上に保存されないので、次回以降そのアプリを開くときまた、ローカルから選択するかたちになってしまいますので注意してください。

おわりに

どちらの方法にしてもちょっとひと手間必要なのは変わらないので、お好きな方法を選択してください。

個人的には後者のほうが、ユーザがアプリに加える変更が少ないので、変更漏れなどを考慮すると後者のほうがいいんじゃないかな?と思います。

ただし、後者のやり方はまだ、実験段階の方法を用いているので、フォーマットが変更される可能性があることに注意してください。

質問や指摘がありましたら、お気軽に尋ねてくださいー。

では。

Power Apps でSharePoint のドキュメントライブラリを再現する

はじめに

今回はPower Apps でSharePoint のドキュメントライブラリを再現してみようと思います。
完成イメージはこんな感じ。

f:id:koruneko:20210627173823g:plain

"進むボタン"と"戻るボタン"の実装が鬼門ですかね。

PowerApps でSharePoint のドキュメントライブラリを再現する

ドキュメントライブラリの情報を取得する

まずはSharePoint のドキュメントライブラリの情報を取得します。

"データの追加"より”SharePoint”を選択します。

f:id:koruneko:20210627174859p:plain

右にでてきたメニューより、取得したいサイトを選択し、"ドキュメント"を選択します。

f:id:koruneko:20210627175140p:plain

これにより選択したサイトのドキュメントライブラリの情報が取得できます。
中を見てもらえればわかる通り、フォルダ / ファイルの数だけレコードが存在しています。

こちらのデータソースにも他と同様委任問題が発生しますので、コレクションに格納しておきます。

Screen.OnVisible

ClearCollect(documentsLib, ドキュメント);

ドキュメント情報を表示する

先ほど取得した情報をもとに、ドキュメント情報を表示させたいと思います。

ここで、取得した情報はファイル / フォルダーの数だけレコードが存在しているので、そのままギャラリーの Itmes に設定してしまうときちんとした階層で、ファイル / フォルダが表示できません。

そこで、現在表示中のディレクトリのみをフィルタリングして表示するように今回はしたいと思います。

ディレクトリの情報は {Path} に設定されています。

f:id:koruneko:20210627182125p:plain

ただ、Filter 関数などで列を指定するときは {Path} ではなく フォルダーのパス という列名で指定してあげる必要があるので、注意してください。
* 設定が日本語の場合

ギャラリーを設置して、 Items に以下を設定します。

Gallery.Items

Filter(documentsLib, フォルダーのパス = "Shared Documents/")

これにより、ホームディレクトリである、"Shared Documents/" 配下の情報のみがフィルター表示されるようになります。

あとは、ドキュメントライブラリやサンプルのような表示になるように、コントロールを配置して式を設定します。

参考までに列の情報を記載しておきます。

列名 設定内容 使用例
Thumbnail サムネイル
*ドキュメントライブラリで
使われているようなアイコンではありません
ThisItem.Thumbnail.Large
拡張子付きのファイル名 拡張子のついたファイル名
フォルダの場合はフォルダ名
ThisItem.拡張子付きのファイル名
登録日時 ファイル / フォルダを作成した日時 ThisItem.登録日時
登録者 ファイル / フォルダを登録したユーザの情報 ThisItem.登録者.DisplayName
更新日時 ファイル / フォルダを更新した日時 ThisItem.更新日時
更新者 ファイル / フォルダを更新したユーザの情報 ThisItem.更新者.DisplayName
フォルダーである フォルダの場合はTrue ThisItem.フォルダーである

よく使うのはこのぐらいでしょうか。
サムネイルですが、記載している通りSharePoint のドキュメントライブラリで使用されているようなアイコンではないことに注意してください。
文字通りサムネイルです。
Excel であれば、シートのスクショした情報、画像であれば、その画像などが設定されています。

あとは、わかりやすくタイトルのラベルを設定してあげればそれっぽくなりますね。

f:id:koruneko:20210627191435p:plain

ディレクトリを移動できるようにする

続いてディレクトリを移動できるようにします。

ユーザの選択によって、フィルターするパスの条件を変更すれば、ディレクトリを移動しているようにみせることができます。

ユーザのカレントディレクトリを判断する方法ですが、コレクションに設定された情報をごにょごにょすることによって判断しようと思います。
何故テキストで保持するのではなく、わざわざコレクションでディレクトリ情報持つの?というと、進む / 戻るボタンを実装するためです。
詳細は次のセクションで説明します。

ディレクトリ情報を格納するためのコレクションを宣言します。

Screen.OnVisible

ClearCollect(
    selectHistory,
    {id:1, dir:"Shared Documents", isCurrent:true}
)

id は連番、 dirディレクトリの名前、 isCurrent には現在ユーザがそのディレクトリにいるのであれば true を、いないのであれば、 false を設定します。

このコレクションの内容をもとに、ディレクトリのフルパスをラベルに表示させます。
このラベルの内容をもとにフィルターを行うようにしたいので、 {Path} と同じフォーマットで表示させます。

currentDirLbl.Text

Concat(
    Filter(
        selectHistory,
        id <= LookUp(selectHistory, isCurrent = true, id)
    ),
    dir & "/"
)

簡単に説明しますと、ユーザが現在いるディレクトリより前のディレクトリ( id )でフィルタリングして、dir に設定されている、ディレクトリ名を "/" で繋げて1つの文字列としています。

このラベルのテキストをもとに、フィルタリング処理を行いたいので、以下のように設定します。

Gallery.Items

Filter(documentsLib, フォルダーのパス = currentDirLbl.Text)

次にフォルダーを選択したときに、選択したディレクトリ情報をコレクションに設定する処理を記載します。

ユーザがフォルダを選択したときには以下の処理を行う必要があります。

  1. ユーザが選択したディレクトリをコレクションに設定
  2. カレントディレクトリの変更

1の処理はコレクションにレコードを追加してあげればよいです。
2の処理は、先ほどまで isCurrenttrue だったレコードの isCurrentfalse に設定してあげればよいです。

2の処理を実現するために、先ほどまでのカレントディレクトリがどれだったか?
を記憶するための変数が欲しいので、 oldCurrentId を設定します。

Screen.OnVisible

UpdateContext({oldCurrentId:LookUp(selectHistory, isCurrent = true, id)});

これで、1, 2を実装する準備が整いましたのでさっそく実装していきます。

Label.OnSelect

UpdateContext({oldCurrentId:LookUp(selectHistory, isCurrent = true, id)});
Collect(
    selectHistory,
    {
        id:LookUp(selectHistory, isCurrent = true, id) + 1,
        dir:ThisItem.名前,
        isCurrent:true
    }
);
UpdateIf(selectHistory, id = oldCurrentId, {isCurrent:false})

これで、ディレクトリの変更が実装できました!

進む / 戻る機能を実装する

いきなり、実装やロジックを文字で解説する前に簡単にそれぞれのボタンが押されたときの動作を図示したいと思います。

それぞれの操作を行うと、 selectHistory コレクションは以下のような動きになります。

戻るボタンを選択したとき
f:id:koruneko:20210627195838p:plain

進むボタンを選択したとき
f:id:koruneko:20210627195906p:plain

薄い青になっているラベルがユーザのカレントディレクトリです。

図のように、進む / 戻るボタンを押してもレコード数は変化させません。(追加も削除も行わない。)
コレクションのレコード数が変化するのは、ユーザがフォルダーを選択したときだけです。

こうしないと、戻るや進むを選択したときにユーザの選択履歴とは異なる情報が保持されてしまい、正しく機能しなくなってしまいます。

以上を踏まえて、実装を行ていきます。

戻るボタンは、カレントディレクトリを1つ前のものに戻す操作ですので、以下で実現できます。

BackIcon.OnSelect

UpdateContext({oldCurrentId:LookUp(selectHistory, isCurrent = true, id)});
UpdateIf(selectHistory, id = oldCurrentId, {isCurrent:false});
UpdateIf(selectHistory, id = oldCurrentId - 1, {isCurrent:true});

戻るボタンは、カレントディレクトリを1つ先のものにする操作ですので、以下で実現できます。

fowardIcon.OnSelect

UpdateContext({oldCurrentId:LookUp(selectHistory, isCurrent = true, id)});
UpdateIf(selectHistory, id = oldCurrentId, {isCurrent:false});
UpdateIf(selectHistory, id = oldCurrentId + 1, {isCurrent:true});

また、戻るボタン、進むボタンともに、戻る先や進む先がないのに押されてしまうと困ります。
よって、戻る先がないときは戻るボタンを非活性に、進む先がないときは進むボタンを非活性にします。
これは皆さんが普段お使いのブラウザでも同じ動作を行っているはずです。

戻るボタンは、カレントディレクトリのレコードの id ( isCurrenttrue のレコードの id )より、小さい id がなければ、もう戻れる先がないので、非活性にします。

BackIcon.DisplayMode

If(First(Sort(selectHistory, id, Ascending)).id < LookUp(selectHistory, isCurrent = true, id),
    DisplayMode.Edit,
    DisplayMode.Disabled
)

進むボタンはカレントディレクトリーのレコードの id より大きいものがなければ、もう進む先がないので、非活性にします。

fowardIcon.DisplayMode

If(Last(Sort(selectHistory, id, Ascending)).id > LookUp(selectHistory, isCurrent = true, id),
    DisplayMode.Edit,
    DisplayMode.Disabled
)

最後に、戻るボタンを押してそこでユーザがディレクトリを選択したとき。
そのディレクトリよりあとのディレクトリの情報は削除しなくてはならないので、以下の式を設定します。

Label.OnSelect

RemoveIf(selectHistory, id > oldCurrentId);

この式は、新たにレコードを追加する前に行う必要がある( id の連番に整合性をもたせるため)
Collect の前に行います。

Label.OnSelect

UpdateContext({oldCurrentId:LookUp(selectHistory, isCurrent = true, id)});
RemoveIf(selectHistory, id > oldCurrentId);
Collect(
    selectHistory,
    {
        id:LookUp(selectHistory, isCurrent = true, id) + 1,
        dir:ThisItem.名前,
        isCurrent:true
    }
);
UpdateIf(selectHistory, id = oldCurrentId, {isCurrent:false})

以上で、Power Apps でドキュメントライブラリの再現ができました!

おわりに

ちょっと前までは、Power Apps からSharePoint のドキュメントライブラリの情報を取得するのはちょっとめんどうだった(はず)ですが、リストを選択する際に”ドキュメント”を選択すれば簡単に取得できるようになりました。

今度は、Power Apps からSharePoint のドキュメントライブラリへファイルをアップする方法を纏めたいと思います。
業務連絡ですが、Power Apps からアップしたExcel ファイルをPower Apps で表示する(列が可変のもの)というのはちょっと実現できなさそうです。。。

不明点や誤りなどありましたら、遠慮なく指摘してくださいー。

Power Apps からSharePoint リストの添付ファイル列へのファイルの登録について

はじめに

Power Apps からSharePoint リストの添付ファイル列へファイル登録について、検証を行いましたので、そのメモをの記載します。

Power Apps からSharePoint リストへのアイテム追加方法

Power Apps からSharePoint リストへアイテムを追加する方法は以下3つがあります。

* 今回はPower Apps から直接登録する方法に絞っているので、Power Automate などから登録する。というのは省いています。

データソースへの登録方法比較

SubmitForm 関数を利用する

こちらは、馴染み深い方も多いのではないでしょうか。
データソースをもとに作成されたアプリでもアイテムの作成に用いられているのはこちらの関数になります。

フォームコントロールを追加して、そのフォームコントロールの内容をSubmitForm 関数でデータソースへ登録する。
という流れですね。

f:id:koruneko:20210620053327p:plain

こちらの方法だと、問題なくデータソースへファイルを登録することができます。
もちろん複数ファイルも可能です。

Patch 関数を利用する

続いて、Patch 関数を用いてのアイテムの追加です。

Patch 関数でのデータ登録はエラーが取得できるので便利ですよね。

添付ファイルコントロールで、追加したファイルの情報は Attachments に含まれているので、こちらを渡すことにします。

Patch(AttachmentControle, Defaults(AttachmentControle), {Title:"Patch", 添付ファイル:DataCardValue2_1.Attachments})

f:id:koruneko:20210620054231p:plain

型が違うと怒られました。
添付ファイルの型は "Attachment" なのに、渡そうとしているのは "Table" だという。エラーですね。

ちなみにSharePoint での添付ファイル列の型(種類)の確認方法SharePoint リストに"添付ファイル"列を追加する(できない)で記載していますので、ご確認ください。

こちらの公式ドキュメントからもわかる通り、Power Apps のキャッバスアプリに Attachment なんて方は存在しません。

docs.microsoft.com

よって、Patch 関数を使って添付ファイルの追加はできなさそうですね。

なおこれは、なぜエラーにならないのか不明ですが、添付ファイル列にコントロールを渡すとエラーがでませんでした。

Patch(AttachmentControle, Defaults(AttachmentControle), {Title:"Patch", 添付ファイル:DataCardValue2_1})

f:id:koruneko:20210620055051p:plain

ただ、これで実行しても、ファイルの情報ではなく、添付ファイルコントロールのプロパティを渡しているだけですので、ファイルの追加はできません。
また、コントロールであればなんでもよく、ボタンを指定してもエラーにはなりませんでした。

よくわからん。。。

Collect 関数を利用する

最後にCollect 関数を用いてアイテムの追加を行う方法についてです。

この方法は公式のサンプルアプリなどではあまり利用されていないやり方ですので、ご存じない方も多いですが、Collect 関数でもSharePoint リストの更新できちゃうんですよね。

先ほどのPatch 関数のときと同じ要領でアイテムの追加を試みます。

Collect(
    AttachmentControle,
    {Title:"Collect", 添付ファイル:DataCardValue2_1.Attachments}
)

f:id:koruneko:20210620055901p:plain

ここでも同じエラーで型が違うと怒られちゃいましたね。

ただ、Patch 関数のときと、まったく同じ動作。というわけではなく、Collect 関数内で添付ファイル列にコントロールを指定したら、型が違うって怒られるんですよね。

f:id:koruneko:20210620060305p:plain

Patch 関数の動作がなにかおかしいような気がしますので、ここでエラーが起きるのはいいですが、、、うーーーん。。。。

いずれにしてもCollect 関数でも添付ファイルの追加はできなさそうですね。

おわりに

以上。検証結果をただ纏めただけでした。

Power Apps で添付ファイルの追加を行いたい場合はSubmitForm 関数を利用するか、Power Automate を利用するようにしましょう。

誤りや質問ありましたら、よろしくお願いしますー。

SharePoint リストに"添付ファイル"列を追加する(できない)

はじめに

タイトルの通りです。

SharePoint Online にて列の種類が"添付ファイル"のものをテンプレートから作成されるもの(列名:"Attachments" もしくは "添付ファイル")とは別に新規で"添付ファイル"列の作成を試みましたが、どうやら現時点ではできないようでした。

参考までに試した方法などをメモしたおきます。

既存の添付ファイル列の情報を確認する

列の作成を試みる前にテンプレートから作成される、添付ファイル列の情報を確認しておきます。

この情報は以下から確認を行いました。

  1. サイト コンテンツへアクセス
  2. 特定のリストへマウスを合わせて"︙"より、"設定"を選択
  3. "列"より、適当な列を選択(* ここでは添付ファイル列は表示されていません)
  4. URL の Field=[列名] の箇所(最後にあります)を Field=Attachments に変更して読込

f:id:koruneko:20210620050152p:plain

この列の種類は"添付ファイル"のようですね。

画面から追加を行う

リストの"列の追加"から追加を試みる

リストの"列の追加"より、リストに列の追加が行えます。
しかし、ここで選択できる種類には"添付ファイル"は現時点では存在しないので、この方法では今回の問題を解決することはできません。

f:id:koruneko:20210620041920p:plain

設定から列の追加を行う

先ほどの画像内で、下部に"その他"を選択すると、設定画面から列の追加を行うことが可能になります。

f:id:koruneko:20210620042120p:plain

この画面は、リストの設定画面から、"列の作成"を選ぶことでアクセスすることも可能です。

f:id:koruneko:20210620042316p:plain

ただ、ここにも"添付ファイル"はいないですね。

よって、画面から"添付ファイル"列を追加することは現時点ではできません。

PowerShell から列の追加を行う

画面から設定できない列の種類もPowerShell からであれば、追加できるものも一部あります。

SharePoint で使用されている、列の種類の一覧はこちらのdocs にて確認することができます。

docs.microsoft.com

"添付ファイル"は"Attachments"になりますので、こちらを種類に指定して列の追加を試みます。

なお列の追加にはPnP.PowerShell を利用します。
PnP.PowerShell の利用方法については、PnP.PowerShell を利用するで纏めていますので、こちらを参考にしてください。

SharePoint Online へアクセス、また対象のリストが作成されている。
という前提のもと、以下コマンドを実行して、添付ファイル列の追加を行います。

Add-PnPField  `
    -List "Lists/${listname}" `
    -DisplayName "添付" `
    -InternalName "Attachments" `
    -Type Attachments `
    -AddToDefaultView

実行の結果以下のようなエラーが発生しました。

Line |
15 | Add-PnPField `
| ~~~~~~~~~~~~~~~
| id (Parameter 'Field already exists')

うーーん。。。
対象のフィールドは既に存在している。と怒られているということは、"添付ファイル"列は1つしか作成できないんですかね?

おわりに

公式ドキュメントなどでできない。と明記されたものが見当たらなかったのですが、そのような記載があるドキュメントってないんですかね?

PnP.PowerShell を利用する

はじめに

PnP.PowerShell を利用するにあたり、ちょっと躓いたので備忘録も兼ねて手順と詰まった点纏めます。

SharePointPnPPowerShellOnline を利用している場合

現在SharePointPnPPowerShellOnline を利用していたユーザーはSharePointPnPPowerShellOnline は古いので新しいやつ入れろよ。てきなメッセージがでている可能性があります。(このメッセージメモしとくの忘れた。。。)

その場合は以下コマンドで事前にSharePointPnPPowerShellOnline をアンインストールしておきましょう。

Uninstall-Module -Name SharePointPnPPowerShellOnline -AllVersions -Force

PnP モジュールのインストール

PnP モジュールのインストールを行います。
管理者権限でPowerShell を開いて以下コマンドを実行します。

Install-Module -Name PnP.PowerShell

PnP モジュールを利用してSharePoint Online へアクセスしてみる

以下コマンドでSharePoint Online へアクセスしてみます。
[YOUR TENANT] には自身のテナントを、 [SharePoint SITE] にはアクセスしたいSharePoint サイトを入力してください。

$url = 'https://[YOUR TENANT].sharepoint.com/sites/[SharePoint SITE]'

Connect-PnPOnline -Url $url -Credentials (Get-Credential)

上記を記載した、コードを実行すると、Credential 情報(ログイン情報)が聞かれますので、設定したSharePoint サイトに対して適切な権限のあるアカウントでログインします。

その結果以下のようなメッセージが表示されたかと思います。

Line | 3 | Connect-PnPOnline -Url $url -Credentials (Get-Credential) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | AADSTS65001: The user or administrator has not consented to use the application with ID '31359c7f-bd7e-475c-86db-fdb8c937548e' named 'PnP | Management Shell'. Send an interactive authorization request for this user and resource. Trace ID: 00e3e933-a737-4c20-b619-7ef4ba9c6600
| Correlation ID: c4cee3cf-b64b-4e42-819b-e02c2aa85e4b Timestamp: 2021-06-19 17:39:32Z

どうやら 'PnP Management Shell' というアプリが許可されてないからブロックされてるっぽいことをいわれた。

ただ、管理センターでSharePoint の項目を探してみたが、アプリを許可するっぽい項目は見当たらなかった。(見落としていましたら教えてください)

自身のテナントにPnP Manager Shell をインストールする

2種類のインストール方法を記載しますが、恐らく1つめの"ドキュメントに記載のやり方"で行ったほうがいいと思います。

ちなみに私は、インストール実施時は、1つ目の方法知らなかったので2つ目の方法でインストールを行ったので、できないことはないです。
ただ、このやり方は古いやり方ですね。

また、本情報をご教示してくださった、@shibatea365 さんありがとうございます!

ドキュメントに記載のやりかた

こちらのドキュメントにて、初回利用時に実行する必要があるコマンドが記載されています。

pnp.github.io

PnP PowerShell allows you to authenticate with credentials to your tenant. However, due to changes in the underlying SDKs we require you first to register a Azure AD Application which will allow you to authenticate.

The easiest way to do this by using a built-in cmdlet:

Azure AD にアプリケーション登録するっぽいですね。

以下コマンドを実行して、PnP Manegement Shell の登録を行います。

Register-PnPManagementShellAccess

このコマンドはAzure AD への書き込み権限のあるアカウントで実行してください。

上記とは別のやり方

調べた結果PnP のリポジトリにて以下のようなissues が上がっていた。

github.com

このissues の中にて以下のようにコメントされている。

github.com

Hi, Thanks for using PnP. In order to apply the template, you need to have the PnP Management Shell app properly configured in your target tenant. We are working on releasing a new cmdlet in PnP PowerShell to ease and speed up the registration process. In the meantime, if you like, you can follow these steps (just the very first time):

どうやら、もっと簡易的に利用ができるように現在開発を進めているところらしいが、現時点では初回利用時は以下コマンドでPnP Management Shell をインストールする必要があるようだ。

Connect-PnPOnline -Url "https://[YOUR TENANT].sharepoint.com/" -PnPManagementShell

このコマンドをPowerShell で実行すると以下のような警告が表示される。

警告:
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXX to authenticate.

記載の通り、 https://microsoft.com/devicelogin へアクセスし、表示されているコードを入力する。
その後は画面に従って許可を行う。

以上でテナントにPnP Manager Shell をインストールすることができた。

先ほどPowerShell で実行したコマンドはずっと実行中扱いになっている場合は、しばらく様子みて、状況変わらなけば Ctrl + C で終了してしまっても問題なかった。

PnP モジュールを利用して指定のサイトにリストを作成してみる

以下コマンドで、SharePoint サイトにリストを作成してみる。
* サンプルなので、記述は最小限

$url = 'https://[YOUR TENANT].sharepoint.com/sites/[SharePoint SITE]'

Connect-PnPOnline -Url $url -Credentials (Get-Credential)

New-PnPList -Title "newSampleList" `
            -Url "Lists/newSampleList" `
            -Template 100

-Title は作成するリストの名前。
-Url は作成するリストのディレクトリ。
-Template は使用するリストテンプレートの値を記載しています。
100 だと、カスタムリスト(GenericList)を利用するということになります。

その他のテンプレートはこちらを参照。

docs.microsoft.com

無事指定のSharePoint サイトにリストが作成できたかと思います。

おわりに

もし認識誤っている箇所などありましたらご指摘いただけますと助かります。

特定のデータの詳細画面を表示する

はじめに

Power Apps でSharePoint リストやDataverse などからアプリを作成できることは皆さんご存じでしょうか?

上記のデータソースをもとにアプリを生成することで以下のような3画面を生成することができます。

一覧画面
f:id:koruneko:20210614221539p:plain

詳細画面
f:id:koruneko:20210614221804p:plain

編集画面
f:id:koruneko:20210614221852p:plain

今回は通常のリンクを開いたときは、"一覧画面"を表示させ、特定の方法から開いたときは、"特定レコードの詳細画面"を表示させるようにしたいと思います。

アプリの作成

SharePoint リストをもとにアプリを作成する

今回は簡単にSharePointリストをもとにしてアプリを作成したいと思います。
作成方法がわからない方向けに、簡単に作成方法を纏めます。
作成方法がわかっている方はこの章を飛ばしてください。

作成方法は大きく分けて2パターンあります。
まずは、SharePoint 側から作成する方法。

  1. もとにしたいSharePoint リストを選択して、 統合 > PowerApps > アプリの作成 を選択します。
    f:id:koruneko:20210614222946p:plain

  2. 適当なアプリ名を入力して作成を押します。 f:id:koruneko:20210614223444p:plain

これだけで、アプリが作成できます!簡単ですね!!

続いてPowe Apps から作成する方法です。

  1. 新しいアプリ > キャンバス を選択します。

  2. SharePointを選択して、もとにしたいSharePointリストを選択します。
    f:id:koruneko:20210614223653p:plain

こちらもたったこれだけでアプリが作成できます!

両者の(個人的な)欠点としては、レイアウトが"携帯電話レイアウト"しか選べない点ですかね。
個人的には"タブレットレイアウト"も選べるようになるといいんですがね。。。
設定から"タブレットレイアウト"に変更も可能ですが、ここから変更すると XWidth に設定してある式が解除されて固定値になっちゃうんですよね。。。面倒くさい。

アプリの開き方によって表示する画面を変更する

アプリの開き方によって表示する画面を変更する。ということを実現するために、アプリを開いたときに渡すパラメータを変えれば条件分岐を行うことができます。

Power Apps でアプリを開くときにパラメータを渡すには、Param 関数を利用すればよいです。

Param 関数とは

Param 関数は、アプリに渡されたパラメーターをアプリの起動時に取得します。 名前付きパラメーターが渡されていなかった場合、Param は 空白 を返します。

です。

Param 関数の使い方は、Yellow さんが纏められているParam関数で外部から値を受け取り、アプリを制御するを参考にしてください。

今回は画面遷移するだけでなく、特定のレコードの詳細画面を表示した画面を表示させたいと考えています。

詳細画面("DetailScreen1")は、どうやって特定レコードの詳細画面を表示しているのか実際の画面をみて確認してみます。

詳細画面でレコードの情報を表示しているのは、"DetailForm1"というフォームです。
こいつの Item をみてみると、 BrowseGallery1.Selected となっていますので、どうやら "BrowseScreen1" のギャラリーで選択されたレコードをここでは表示しているようです。

今回ここの処理は変えずに、また干渉せずに、追加の処理を記載するだけでやりたいことを実現させようと思います。

処理を変えずに。ということなので、素直に表示させたいレコードのあるギャラリーを選択することにしたいと思います。
ギャラリーの特定レコードを選択するために、Select 関数を用いたいと思います。

Select( Control, Row or column) とすることで、"Row or colum"番目のレコードを選択することができます。

この番号は今回、SharePoint リストにて連番がつけられる ID を用いて判断したいと思います。

ちなみに ID とはSharePointリスト作成時に設定される項目で、列の種類は"カウンター"になっています。

f:id:koruneko:20210615000731p:plain

ただ、そのまま ID を利用すると、レコードが途中で削除されたときに困ってしまうので

CountRows(Filter(BrowseGallery1.AllItems, ID <= Value(Param("_ListID"))))

として、対象レコードが何番目のレコードなのかを判断するようにします。

さて、ギャラリーを選択するためにSelect 関数を用いるわけですが、このSelect 関数は対象コントロールが同一画面に存在しないと実行することができません。
つまり"BrowsScreen1"内に設定しなくてはいけないので、 App.OnStart には設定できません。

また、ギャラリーを選択するわけですので、ギャラリー内にアイテムがセットされている必要があります。

これらの条件を満たせるように設定を行っていきます。

まず画面遷移を行う条件を再度確認すると、

  • Param が設定されている場合
  • ギャラリーにアイテムが設定されている場合

です。

これらの条件を満たすときに画面遷移。としたいので、トグル(切り替え)コントロールを利用します。

トグルの Default に以下を設定して、上記の条件を式で表します。

Toggle1.Default

!IsBlank(Param("_ListID")) && !IsEmpty(BrowseGallery1.AllItems)

このトグルが true になったとき。つまりチェックされたときギャラリーを選択して画面遷移を行いたいので、 OnCheck に以下を設定します。

Toggle1.OnCheck

Select(BrowseGallery1, CountRows(Filter(BrowseGallery1.AllItems, ID <= Value(Param("_ListID")))));

これでギャラリーのN 番目の項目を選択したことになりますので、ギャラリー内の OnSelect が動作し、"DetailScreen1"へ画面遷移を行います。

動作確認

アプリ保存 / 公開後、アプリの詳細を開き、Web リンクをコピーします。

https://apps.powerapps.com/play/アプリID?tenantId=テナントID

となっているやつです。

まずはこれに直接アクセスしてみたください。

"一覧画面"が表示されたかと思います。

続いて先ほどのリンクにパラメータ値を設定して、開いてみます。

https://apps.powerapps.com/play/アプリID?tenantId=テナントID&パラメータ名=値

先ほど作成したアプリですと、

https://apps.powerapps.com/play/アプリID?tenantId=テナントID&_ListID=2

となりますね。

こちらのリンクからアプリ開いてみると2番目のレコードが表示されたかと思います。(ID = 1を削除していなければ。)

おわりに

この処理を活用することで、承認フローなどで、申請内容の詳細をPower Apps で表示するためのリンクを作成したりすることが可能です。

ただし今回のやり方には1つ欠点があります。
それは、一瞬"一覧画面"が表示されてしまうという点です。

そのぐらいであれば、別に気にしない。と割り切れるのであればよいですが、そうでない場合何らかの工夫が必要になってきます。


スポンサードリンク