Quantcast
Channel: tyoshikawa1106のブログ
Viewing all 1438 articles
Browse latest View live

SFDC:Lightningコンポーネントの開発でコンポーネントの有効性チェックする方法


SFDC:Winter18のコラボレーション売上予測機能強化

$
0
0

Winter'18でLightning Experienceの売上予測機能でできることが増えています。
f:id:tyoshikawa1106:20180401223359p:plain

リリースノート


下記のような特徴の機能が追加されています。

  • アクセス権があるユーザの売上予測にジャンプして表示する
  • 目標達成率情報を表示する
  • Lightning セールスコンソールでコラボレーション売上予測にアクセスする。
  • 自分の商品ファミリの売上予測を調整する。これは、Lightning Experience に固有の機能です。

SFDC:Winter18のQuipドキュメントとの連携強化について

$
0
0

Winter'18からQuip ドキュメントとの連携がより便利になったそうです。複雑な認証設定をしなくても簡単にQuipとSalesforce間でドキュメントのやりとりが可能になっています。
f:id:tyoshikawa1106:20180401223733p:plain

リリースノート

SFDC:Winter18のLightning Experienceダッシュボード埋め込み機能について

$
0
0

Winter18からLightning Experienceのホームタブとアプリケーションページにダッシュボード埋め込みができるようになったとのことです。
f:id:tyoshikawa1106:20180401223951p:plain

リリースノート

SFDC:Lightning Experienceで使えるChatterの絵文字機能について

$
0
0

Winter'18からLightning ExperienceでもChatterの絵文字機能が利用できるようになったみたいです。Classicと同じで設定で有効化する必要はあると思います。
f:id:tyoshikawa1106:20180401224156p:plain

リリースノート

SFDC:Lightning Experienceで使えるテリトリー機能について

$
0
0

Winter'18からLightning Experienceでテリトリー機能が使えるようになったみたいです。名称はエンタープライズテリトリー管理です。
f:id:tyoshikawa1106:20180401224350p:plain

リリースノート

SFDC:Apexテストクラス開発で使える並列テストの実行オプション

$
0
0

Winter'18から下記のアノテーションが追加されたそうです。並列テストの実行オプションとのことです

@isTest(isParallel=true)


f:id:tyoshikawa1106:20180401224607p:plain

リリースノート

SFDC:Winter18のSalesforceDXに関する情報

$
0
0

もうSpring'18のリリースノートが公開されているので情報が古いかもしれませんがWinter18のSalesforceDXに関する情報がリリースノートにまとめられています。
f:id:tyoshikawa1106:20180401224902p:plain

リリースノート


役立つリンクが紹介されているかもしれません。
f:id:tyoshikawa1106:20180401224934p:plain


SFDC:APIバージョン41.0以降のLightningコンポーネント開発について

$
0
0

APIバージョン41.0以降のLightningコンポーネント開発ではコンポーネントコードの保存時の自動検証が実行されるようになっているそうです。APIバージョンを最新にして開発していくようにした方がよさそうです。

f:id:tyoshikawa1106:20180401225218p:plain

リリースノート

SFDC:活動のアーカイブと活動関連リストについて

$
0
0

Salesforceには1年間経過した活動はアーカイブされる仕組みがあります。これはデータが削除されるわけではなくレポート、リストビュー、検索でヒットしなくなるという仕様になっています。
f:id:tyoshikawa1106:20180401230030p:plain

レポートに全ての活動(ToDo および行動)が表示されない


なので一番重要な活動関連リストにはアーカイブ後も引き続き表示されるようになっています。(すべて表示ボタンで表示される)
f:id:tyoshikawa1106:20180401230230p:plain

アーカイブ済み活動の表示

SFDC:自動採番項目の表示形式変更を試してみました

$
0
0

Salesforceの自動採番項目の表示形式変更を試してみました。
f:id:tyoshikawa1106:20180404142801p:plain


Salesforceの自動採番項目を導入するときにうっかり「A-0001」と指定してしまうことがあると思います。基本的に任意の値に切り替えることはできませんが特定の手順で変更することが可能です。

f:id:tyoshikawa1106:20180404142844p:plain

※変更の際は必ずデータ入力が行われていない時間帯に作業します。


作業の流れ

まずはデータローダで既存データをエクスポートします。
f:id:tyoshikawa1106:20180404143004p:plain


続いてCSVデータを加工します。この作業はGoogleドライブにCSVファイルをアップしてGoogleスプレッドシートで行うとスムーズです。
f:id:tyoshikawa1106:20180404143150p:plain


別の列で新しい連番を用意したあとに既存の列の情報を更新します。
f:id:tyoshikawa1106:20180404143224p:plain


加工完了したらCSVファイル形式でダウンロードします。これで更新用データの準備ができました。
f:id:tyoshikawa1106:20180404143348p:plain


続いてName項目のデータ型をテキスト型に変更します。
f:id:tyoshikawa1106:20180404143301p:plain


テキスト型に変更するとName項目の値を更新することができるようになります。先程用意したCSVファイルとデータローダをつかってUPDATE作業を行います。(マッピングでName項目が表示されていない場合は、データローダを一度ログアウトして再ログインすると表示されます。)


UPDATE完了後にデータが正しく変更されているかを確認します。
f:id:tyoshikawa1106:20180404143413p:plain


更新に問題がないことを確認したらデータ型を自動採番型に変更します。そのとき開始番号には既存データの次の番号をセットします。
(選択リストで自動採番を選び保存を押すと各項目が表示されます)
f:id:tyoshikawa1106:20180404143621p:plain


データ型を自動採番に切り替えた後試しに一件データを作成してみます。
f:id:tyoshikawa1106:20180404143749p:plain


データが作成できることを確認できたら作業完了です。
f:id:tyoshikawa1106:20180404143818p:plain

f:id:tyoshikawa1106:20180404143850p:plain


この作業は他にデータ登録処理が実行されない時間帯に行う必要があります。また自動採番の値をつかって他システムと連携していないかの確認も必要です。作業後はApexクラスのテストがエラーになったりしていないかも確認しておくと無難かもしれません。基本的には変更しないというのが一番ですが他のデータと区別をつけやすくしたいときはこの手順で変更可能のはずです。

SFDC:Magic Mover for Notes And Attachments to Lightning Experience を試してみました

$
0
0

Magic Mover for Notes And Attachments to Lightning Experience を試してみました。メモ&添付ファイルをLightning Experienceがサポートするメモオブジェクトとファイルオブジェクトの形式に変換するためのアプリケーションです。

f:id:tyoshikawa1106:20180408085128p:plain

Magic Mover for Notes And Attachments to Lightning Experience - Salesforce Labs - AppExchange


このアプリケーションはSummer'17でファイルの変換方法として紹介されています。Salesforce社のSalesforce LabsチームがAppExchangeで公開していますが、Sales CloudやService Cloudのようにサポートされている製品ではないと思います)
f:id:tyoshikawa1106:20180408085506p:plain

リリースノート


メモ&添付ファイルの場合、LightningExperineceで参照すると自動でダウンロードされてしまいますが、ファイル形式の場合はプレビューモードが起動されます。そのため、Lightning Experienceの有効化には避けては通れない作業となっています。
f:id:tyoshikawa1106:20180408090039p:plain


アプリの利用ガイドも用意されています。作業の前には確認しておくと良さそうです。Summer'17のリリースノート公開されたときからアプリ名は変更されていたみたいです。
f:id:tyoshikawa1106:20180408090321p:plain

https://appexchange.salesforce.com/servlet/servlet.FileDownload?file=00P3A00000cWkhLUAS


AppExchangeなのでインストールは簡単に実施できます。
f:id:tyoshikawa1106:20180408090538p:plain:w300


ただし、そのままインストールするとエラーになると思います。
f:id:tyoshikawa1106:20180408090601p:plain:w300


このエラーはインストール作業前に必要な設定を行っていないからでした。ユーザインターフェースの設定でチェックを付ける必要があります。(詳細はガイドの方に記載されていました。)
f:id:tyoshikawa1106:20180408090636p:plain


メモ機能の有効化もやっておいたほうが良さそうです。
f:id:tyoshikawa1106:20180408090733p:plain


これで問題なくインストールできると思います。
f:id:tyoshikawa1106:20180408090806p:plain:w300


インストールすると権限セットが追加されます。これを管理者ユーザに割り当てます。
f:id:tyoshikawa1106:20180408090840p:plain


また下記の権限を追加してください。
f:id:tyoshikawa1106:20180408090920p:plain

f:id:tyoshikawa1106:20180408090934p:plain



下記のVisualforceページタブが追加されます。

  • Attachments
  • Attachments to Files
  • Configuration
  • Last Documents
  • Latest Files & Notes
  • Notes Conversion
  • Update Page Layouts


メモ&添付ファイルを移行するのはAttachments to Filesタブのページです。確認時に複数あることに気づかずメモ変換用のNotes Conversionページを起動したのですが、最初にリモートサイト設定の追加が必要になります。おそらく画面にメッセージが表示されるのでボタンをクリックするだけで追加完了です。権限セットが割り当てられていないとここで警告も表示されました。
f:id:tyoshikawa1106:20180408091253p:plain

f:id:tyoshikawa1106:20180408091554p:plain


ひとまずこれで事前準備が整いました。作業前にConfigurationタブにアクセスしてください。ここでバッチサイズを切り替えることが可能みたいです。
f:id:tyoshikawa1106:20180408091755p:plain


ファイル変換処理ですが、何も考えずに実行していくと『Apex CPU time limit exceeded』エラーが発生します。これは1日の使用量をオーバーしたことで発生するのですが、これが発生すると24時間一部機能が利用できなくなります。エラー通知のメールに「サポートに問い合わせて下さい。」と記載ありました。念のために問い合わせてみましたがさすがに緩和とかは難しいみたいでした。(※ファイルの変換作業は一度に処理する件数を減らすことで進めることができました。)


こうしたエラーを回避するためにもバッチサイズを50〜80ぐらいに減らしておいた方が無難かと思います。変換作業を実施したときにはこのページの存在に気づかずに上記CPUタイムの上限エラーを起こしてしました。その後70件から80件だと動くことに気付き毎回手動実行する方法で対応したのですが、本来はこのページでバッチサイズを変更すれば簡単に対応できると思います。



バッチサイズの設定ができたら、Attachments to Filesタブにアクセスします。ここでファイル変換作業を実施できます。
f:id:tyoshikawa1106:20180408092521p:plain


まずは対象ファイルを日付とオブジェクトで絞り込みます。今回変更対象のファイルは長年使われている組織と比べて多くなかったため、全期間と全オブジェクトで取得しても問題ありませんでしたが、必要に応じて絞り込むと良さそうです。条件を指定したらFilterボタンで検索できます。
f:id:tyoshikawa1106:20180408092626p:plain


検索した移行対象は画面左下に表示されます。移行対象にチェックをつけて少し上にあるConvertボタンをクリックします。
f:id:tyoshikawa1106:20180408092927p:plain


最初は検証用に数件試すのが良いと思います。実行前のメモ&添付ファイルはこのようになっています。
f:id:tyoshikawa1106:20180408093201p:plain


Converボタンをクリックするとポップアップで確認メッセージが表示されるので問題なければ実行します。
f:id:tyoshikawa1106:20180408093319p:plain


処理はApexバッチで行われます。完了まで少し時間が掛かります。
[f:id:tyoshikawa1106:20180408093337p:plain:300]


処理が完了するとメールで通知が届きます。ガバナ制限が発生しそうな場合などの通知メールも届くようになっています。
f:id:tyoshikawa1106:20180408093543p:plain


処理完了後はこのようになります。
f:id:tyoshikawa1106:20180408093632p:plain


ファイル関連リストとメモ&添付ファイルに同じものが表示されているのは、Salesforceの仕様なので問題ありません。(ファイル関連リストのデータはメモ&添付ファイルからも参照可能となっています。)


タイトル部分にIDが割り当てられたファイル、これが移行元となったファイルです。
f:id:tyoshikawa1106:20180408093852p:plain


移行元のファイルはAttachments to Filesの機能で削除することが可能です。
f:id:tyoshikawa1106:20180408094045p:plain


ゴミ箱をクリックすると削除バッチが実行されます。
f:id:tyoshikawa1106:20180408094117p:plain


これで不要になったファイルを削除できました。ファイルはゴミ箱にはいかず完全削除されるので注意してください。
f:id:tyoshikawa1106:20180408094232p:plain


この作業が完了した後すぐに対応しなくてはならないことがあります。ページレイアウトの設定です。メモ&添付ファイル関連リストが表示されたままだとまた新たなファイルがアップロードされてしまいます。それを防ぐためにメモ&添付関連リストを除外してファイル関連リストに差し替える必要があります。


こうした作業はUpdate Page Layoutタブの機能を利用すると簡単です。
f:id:tyoshikawa1106:20180408094510p:plain


画面左側のチェックボックスがメモ&添付ファイルが表示されているページレイアウトを表します。画面右側のチェックがファイル関連リスト・メモ関連リストを表示していることを表しています。関連リストの追加と除外は右上のボタンから実行できました。
f:id:tyoshikawa1106:20180408094832p:plain:w300



これでMagic Mover for Notes And Attachments to Lightning Experienceをつかってファイル関連リストへの変換が完了しました。メモの方は試していませんが同じように実行できると思います。この機能は正式な製品ではないと思いますので基本的には自己責任での利用が求められると思います。利用前には事前の検証を必ず行うようにした方が良さそうです。


注意点として、このパッケージのApexクラスがテストクラスでエラーが発生しました。インストール中はリリース作業ができなくなる可能性があります。(パッケージではなく組織側の問題かもしれません。)


検証時にはその当たりも含めて確認しておくのが良さそうです。


正式な製品ではありませんが、Salesforceのチームが公開しているためかTrailblazerCommunityにグループが用意されています。そこで最新情報を取得したり質問したりができそうです。
f:id:tyoshikawa1106:20180408095242p:plain
https://success.salesforce.com/_ui/core/chatter/groups/GroupProfilePage?g=0F93A000000LgpSSAS

補足

メモ&添付ファイル関連リストはAttachmentオブジェクトでしたが、ファイル関連リストのデータはContentVersion/ContentDocumentで管理されます。Apex側での改修が必要になったり、Force.comサイトのゲストユーザでアクセスできなかったりしますので、開発が入っている組織の場合は移行して問題が内科のチェックを行う必要があります。

SFDC:価格表と商品のメンテナンスを試してみました

$
0
0

Sales Cloudの商談機能を使えば商品の金額を管理できます。商品の管理には価格表が必要になるのですが、値を更新したときの扱いなどについて確認してみました。
f:id:tyoshikawa1106:20180408111303p:plain


商談商品の利用開始にはまず価格表を用意します。用意ができたら商談の詳細ページの商品関連リストから商品を追加ができるようになります。
f:id:tyoshikawa1106:20180408111151p:plain


初回の商品追加は価格表の選択が求められます。
f:id:tyoshikawa1106:20180408111333p:plain


続いて対象の商品を選択します。
f:id:tyoshikawa1106:20180408111417p:plain


数量と金額を入力します。残りの項目は必須ではないので状況に応じて利用します。
f:id:tyoshikawa1106:20180408111446p:plain


これで商品の追加が完了しました。
f:id:tyoshikawa1106:20180408111524p:plain


商品関連リストのすべてリンクをクリックすると選択した商品が一覧表示されます。
f:id:tyoshikawa1106:20180408111613p:plain


登録した商品はもちろん編集可能です。
f:id:tyoshikawa1106:20180408111656p:plain

価格表の更新の影響

ここからが今回の調査対象です。まず選択した価格表の金額が変更された場合、商談商品に影響があるか確認しました。価格表の金額はリスト価格で管理されています。
f:id:tyoshikawa1106:20180408111937p:plain


標準価格表チェックがONになっていると変更できないのでOFFにしてから値を更新します。
f:id:tyoshikawa1106:20180408112042p:plain


これで価格表の金額を更新しました。
f:id:tyoshikawa1106:20180408112112p:plain


その状態で商談商品の金額が変更されているか確認したところ、値は変更されずに残っていました。
f:id:tyoshikawa1106:20180408112227p:plain


価格表の金額を更新しても商談に登録した金額(販売価格)が勝手に変更されることはないようです。ただし、リスト価格の値が異なる値に更新されていました。基本的には問題ありませんが定価と比較してどの程度値下げもしくは値上げされているかが確認できなくなってしまいます。


価格表の金額更新は可能ですが、基本的には行わない方が良さそうです。

新しい価格の追加

上記の通り、価格表の金額を変える時は既存の価格表を更新するのではなく新規価格表を作成する方が良さそうです。その場合は既存価格表をコピーする形で登録できます。
f:id:tyoshikawa1106:20180408112701p:plain


・・・が、コピーした場合は商品データはコピーされないみたいです。。
f:id:tyoshikawa1106:20180408112759p:plain


これに関してはClassicから作成すると商品を含めてコピーできる機能があります。
f:id:tyoshikawa1106:20180408112954p:plain

f:id:tyoshikawa1106:20180408113015p:plain


今後のバージョンアップで対応可能になると思いますがそれまではClassicでの対応が良さそうです。


上記手順で新しい価格表を作成できました。
f:id:tyoshikawa1106:20180408113237p:plain


これで新しい商談を登録する際に金額が変更された価格表を選択できるようになります。
f:id:tyoshikawa1106:20180408113452p:plain


f:id:tyoshikawa1106:20180408113507p:plain


f:id:tyoshikawa1106:20180408113523p:plain

価格表の無効化

新しい価格設定が行われた後、旧価格が登録されてしまうのはあまり良くありません。価格表には無効化の機能もあるので試してみました。
f:id:tyoshikawa1106:20180408113734p:plain


無効になった価格表は次のように選択できなくなります。
f:id:tyoshikawa1106:20180408113951p:plain


ここで心配なのが既に進行済の案件です。これらの商談の価格表が切り替わってしまうと正しい集計ができません。確認したところそれらの価格表は問題なく利用できました。
f:id:tyoshikawa1106:20180408114130p:plain

f:id:tyoshikawa1106:20180408114215p:plain


ただし、価格表を変更してしまうと無効になった価格表は選択できなくなります。(価格表の変更を行うと商品情報もリセットされるので気軽には実施できません。)
f:id:tyoshikawa1106:20180408114434p:plain

商品の無効化

価格表の無効化の挙動は確認できました。最後に商品の無効化について確認します。
f:id:tyoshikawa1106:20180408114530p:plain


新しい商品の提供により古い商品のサポートが終了することがあると思います。そうした商品が商談登録時に選択肢としてでてしまうのは少し不便です。そのため無効化することで整理することができます。商品を無効化すると商談商品の選択肢からは表示されなくなります。
f:id:tyoshikawa1106:20180408114805p:plain


既に登録済の商談商品はそのまま利用できるようです。
f:id:tyoshikawa1106:20180408115011p:plain


価格表にもそのまま登録されていますが、無効なデータとして登録されています。
f:id:tyoshikawa1106:20180408115129p:plain


新規価格表作成時にも選択できなくなります。
f:id:tyoshikawa1106:20180408115227p:plain


商品を無効にすると全ての価格表に影響がでます。ですのでもしも過去の価格表では引き続き利用したい場合は商品を無効にするのではなく価格表から除外するだけの方が良いかもしれません。
f:id:tyoshikawa1106:20180408115343p:plain


価格表と商品のメンテナンスはこんな感じでした。

SFDC:Lightning Loginと Two Factor Authencicationを試してみました

$
0
0

Lightning LoginとTwoFactorAuthencication有効化を試してみました。以前にも試したことのある機能なのですが、久しぶりに設定した際により便利にアップデートされていたので改めてやってみました。

f:id:tyoshikawa1106:20180408144508p:plain


これらの機能を有効化する場合はプロファイルではなく権限セットで個別に設定します。
f:id:tyoshikawa1106:20180408144544p:plain


権限セットのシステムのセクションで下記を有効化します。

  • Lightning Login ユーザ
  • ユーザインターフェースログインの 2 要素認証


用意した権限セットは対象のユーザに割り当てます。
f:id:tyoshikawa1106:20180408144705p:plain


この機能を利用するには専用のアプリが必要です。業務で利用する携帯電話にインストールしておきます。
f:id:tyoshikawa1106:20180408144833p:plain

「Salesforce Authenticator」をApp Storeで


権限を追加すると次回ログイン時に次の画面が表示されます。
f:id:tyoshikawa1106:20180408145101p:plain


先ほどインストールした専用アプリを起動して画面下側にある新規アカウントをタップします。すると2語の語句が表示されます。
f:id:tyoshikawa1106:20180408145308p:plain:w200


これを認証画面に入力して次に進めます。
f:id:tyoshikawa1106:20180408145426p:plain


携帯電話のアプリで承認依頼が届くので承認します。
f:id:tyoshikawa1106:20180408145630p:plain:w200


承認するとログインが実施されて次回ログインからTwoFactorAuthencication (2要素認証)が有効化されます。実際に試してみるとわかりますが、ログインするとアプリの通知が届き、アクセスすると承認ページが表示されています。承認するだけでログイン完了するのでランダムなキーワードを入力する必要はありません。


さらにLightning Login機能を有効化していると次ページが表示されます。
f:id:tyoshikawa1106:20180408145950p:plain

f:id:tyoshikawa1106:20180408150009p:plain


画面に従って有効化と承認を行います。
f:id:tyoshikawa1106:20180408150130p:plain:w200


なお、Lightning Logiinの機能を利用するにはログイン時にユーザ情報を保存しておく必要があります。
f:id:tyoshikawa1106:20180408150252p:plain:w200

f:id:tyoshikawa1106:20180408150148p:plain

※保存しても設定が反映されないことがあるのでLightning Loginが利用できるようになるまで少し時間がかかるのかも知れません。


Lightning Loginなどの無効化はユーザの詳細ページから行うことができます。
f:id:tyoshikawa1106:20180408150557p:plain


また、2要素認証の機能には「ワンタイムパスワードジェネレータ」と「Salesforce Authenticator」の二種類がありますが、基本的にはタップだけで認証できる「Salesforce Authenticator」を利用すればいいと思います。


Lightning Loginは「Salesforce Authenticator」を有効化した後により作業を効率化出来る機能となっています。

Lightning Loginを有効化した後

ログインページにユーザ名が表示されます。
f:id:tyoshikawa1106:20180408150844p:plain


クリックするとアプリに通知が届くので承認します。それでログイン完了です。
f:id:tyoshikawa1106:20180408151016p:plain


TwoFactorAuthencicationのメインであるスマートフォンの承認があればセキュリティが保証されているという考え方だと思います。認証デバイスは複数登録できないと思われます。必ずユーザの手元にある状態であることが重要です。携帯電話を使い回す場合は利用できません。また共用PCへのユーザ登録も避けて下さい。うっかり登録してしまった場合はユーザ詳細ページで無効にします。

関連記事

SFDC:Einsteinハンズオンに参加してサンプルアプリを作ってみました

$
0
0

Einsteinハンズオンに参加してサンプルアプリを作ってみました。
f:id:tyoshikawa1106:20180409170016p:plain

環境の準備

TrailheadのChallengeのところからPlayground環境を作成します。作成したらユーザの言語を英語に変更。
f:id:tyoshikawa1106:20180409153302p:plain


手順に従いオブジェクトを作成

  • Cat オブジェクトを作成する
  • Interested Person オブジェクトを作成する

上記オブジェクトのタブを作成する。
上記オブジェクトタブを含むアプリケーションを作成する。

f:id:tyoshikawa1106:20180409154056p:plain


テストデータを作成する。
f:id:tyoshikawa1106:20180409155114p:plain

f:id:tyoshikawa1106:20180409154321p:plain


次のようなエラーがでたら設定ミス。タブの名前変更が必要。
f:id:tyoshikawa1106:20180409154832p:plain


この設定ページから。ユーザの地域を英語にしておけばオブジェクト作成時に登録できたかも。
f:id:tyoshikawa1106:20180409154920p:plain


グローバル選択リストを作成する。
f:id:tyoshikawa1106:20180409155307p:plain


カスタムオブジェクトに選択リストを割り当てる
f:id:tyoshikawa1106:20180409155438p:plain

f:id:tyoshikawa1106:20180409155732p:plain


こんな感じで使えるようになれば準備OK。
f:id:tyoshikawa1106:20180409155522p:plain

f:id:tyoshikawa1106:20180409155747p:plain


2つのオブジェクトに追加した項目に値をセット。
f:id:tyoshikawa1106:20180409155946p:plain

f:id:tyoshikawa1106:20180409155921p:plain


2つのオブジェクトは参照関係などの紐付けがありませんが、Einsteinでマッピングできるというのが今回の目標みたいです。

追記

Interested Personの方は複数選択リスト型でした。
f:id:tyoshikawa1106:20180409162018p:plain

Einsteinの準備

Einstein プラットフォームサービスアカウントにサインアップする
https://api.einstein.ai/signup


einstein_platform.pemファイルをダウンロードできます。(同じメールアドレスで2つ目は作成できない。過去に作成済みの場合はそちらを利用。)
f:id:tyoshikawa1106:20180409153204p:plain

Salesforce に認証証明書を保存する

静的リソースではなくSalesforce Filesへのアップロードを行う。
f:id:tyoshikawa1106:20180409160437p:plain

f:id:tyoshikawa1106:20180409160510p:plain

未管理パッケージをダウンロード

ダウンロードURLはTrailheadに記載されています。
f:id:tyoshikawa1106:20180409160953p:plain

f:id:tyoshikawa1106:20180409161017p:plain

※事前にユーザのパスワードをリセットして自動生成ではないパスワードを指定すること。

f:id:tyoshikawa1106:20180409161111p:plain


未管理パッケージをインストールするとカスタム設定が追加されています。Einsteinにサインアップしたメールアドレスを登録します。
f:id:tyoshikawa1106:20180409161250p:plain

ApexクラスとLightning コンポーネントとLightningアプリケーションを作成

下記のApexクラスを作成します。(※コードはTrailheadを参照)

  • EinsteinVision_Admin.cls

f:id:tyoshikawa1106:20180409161546p:plain


次にLightning コンポーネントを作成します。

  • EinsteinVision_Admin_UI.cmp

f:id:tyoshikawa1106:20180409161744p:plain


最後にLightningアプリケーションを作成します。これは開発者コンソールではなく設定ページから。
f:id:tyoshikawa1106:20180409162330p:plain

f:id:tyoshikawa1106:20180409162540p:plain

f:id:tyoshikawa1106:20180409162608p:plain

f:id:tyoshikawa1106:20180409162624p:plain

f:id:tyoshikawa1106:20180409162637p:plain

f:id:tyoshikawa1106:20180409162653p:plain

f:id:tyoshikawa1106:20180409162706p:plain


アプリケーションへの追加はLightning Experieneタブを選択してそこで設定。
f:id:tyoshikawa1106:20180409162834p:plain


こんな感じで表示されればOK。
f:id:tyoshikawa1106:20180409162917p:plain

データセットの作成

Einsteinで分析するためのデータ・セットを作成します。

[https://developer.salesforce.com/files/Cats.zip]


URLを貼ってCreateボタンをクリック。こんな感じ。
f:id:tyoshikawa1106:20180409163103p:plain


Refreshするとこうなる。
f:id:tyoshikawa1106:20180409163138p:plain


最後にTrainボタンをクリックすると何かの処理が実行される。
f:id:tyoshikawa1106:20180409163341p:plain


Success100%と表示されたらOK。処理には少し時間がかかります。うっかり二回処理をうごかしたら動いてしまいました。
f:id:tyoshikawa1106:20180409163717p:plain

Cat (猫) オブジェクトに画像認識機能を追加

Lightningコンポーネントを作成
f:id:tyoshikawa1106:20180409163919p:plain


Cat レイアウトに Lightning コンポーネントを追加
f:id:tyoshikawa1106:20180409164031p:plain

猫の画像を分類する

これでアプリの準備が整いました。実際にデータを読み込ませて分類を試します。使うのはこの画像。
f:id:tyoshikawa1106:20180409164155p:plain


ファイルはTrailheadからダウンロード。
f:id:tyoshikawa1106:20180409164228p:plain



ファイルをアップするとデータが更新されることを確認できます。
f:id:tyoshikawa1106:20180409164441p:plain

アプリの利用例:Chatterと連携

グループを3つ作ります。
f:id:tyoshikawa1106:20180409164817p:plain


プロセスビルダーを作成します。
f:id:tyoshikawa1106:20180409165002p:plain


ざっくりこんな感じ。
f:id:tyoshikawa1106:20180409165313p:plain


猫画像をアップロードすると、「Bengal」と判別されて・・・
f:id:tyoshikawa1106:20180409165512p:plain


先ほど作成したプロセスどおりBengalのグループにメッセージが投稿されます。
f:id:tyoshikawa1106:20180409165551p:plain


里親になりたい人はこのChatterグループでメッセージを通知を受けることができるという流れになります。Chatter投稿の部分はおまけ的な感じで画像をアップすると猫の分類が自動で行われ値が更新されたことを確認するというのが今回のハンズオンの目的でした。

f:id:tyoshikawa1106:20180409165758p:plain


認証キーとなるeinstein_platform.pemファイルをSalesforceにアップしてEinstein APIを実行できたのだと思います。今回サンプルコードの中身は確認してみませんがこれをベースにAPIガイドを見ながらいろいろ試せるんだと思います。


SFDC:Salesforce AuthenticatorとApple Watch連携で2要素認証作業の効率化

$
0
0

Salesforce Authenticatorアプリを利用して2要素認証を有効化することでセキュリティをより強化にすることができます。

f:id:tyoshikawa1106:20180412083204p:plain

Two-factor Authentication (2FA)


有効化の方法はこちら。


有効化して数日間試してみたのですが、やはりログイン時にスマートフォンのロックを解除して承認を行うのはなかなかに面倒でした。調べてみたところこの問題の解決方法が見つかりました。


Salesforce Authenticatorアプリですが、Apple Watchアプリもサポートしています。このApple Watchアプリの場合は手につけてロックを解除している状態の場合はすでに安全な状態が確保されています。そのためだと思うのですが、2要素認証の自動承認の機能が利用可能となっていました。


そのためSalesforceにログイン→認証ページが表示→Apple Watchのアプリが自動承認という流れでスムーズにログインすることができます。スマートフォンのロック解除の手間もなくなり非常に便利です。


この運用を行う場合はApple Watchのパスワード設定無しでの運用は禁止にする必要がありそうです。またおそらくスマートフォンが近くにない場合は自動承認が利用できない状態になってくれると思います。(検証はしてないですが)


Apple Watchによる自動承認機能ですが、Lightning Login機能を有効にしている場合は利用できませんでした。Lightning Loginはパスワードを入力不要になるためApple Watchだけでログイン可能になる問題を防ぐためかもしれません。ちなみに下記のページで有効化の要望が上がっていました。

参考

SFDC:SOQLクエリでLightning Experiecneの利用状況を確認

$
0
0

Lightning Expcerience導入後、引き続きClassicを利用しているユーザがどの程度いるかは開発者コンソールからSOQLクエリを実行することで確認できます。


UserPreferencesLightningExperiencePreferredがTrueのものが有効にして使っているものです。

基本のクエリ
SELECT Id,Name, UserPreferencesLightningExperiencePreferred FROM User
プロファイル名判定
SELECT Id,Name, UserPreferencesLightningExperiencePreferred FROM User 
WHERE Profile.Name = 'サンプル' OR Profile.Name = 'システム管理者'
Lightning Expcerience利用していないユーザの判定
SELECT Id,Name, UserPreferencesLightningExperiencePreferred FROM User 
WHERE UserPreferencesLightningExperiencePreferred = false


単純にクエリを実行するとコミュニティユーザや無効なユーザも集計されるのでプロファイル名などで絞り込む必要があります。

関連記事

SFDC:パートナーコミュニティユーザのアクセス権限と所有者の関係

$
0
0

パートナーコミュニティユーザに取引先と取引先責任者の作成権限を付与した場合、別会社の取引先と取引先責任者を作成することができます。その場合は作成者と所有者はパートナーコミュニティユーザとなります。


所有者を社内ユーザに切り替えた場合パートナーコミュニティユーザは自分が作成した取引先のデータでも参照不可となります。(共有設定等で非公開設定している前提です。)


わかってはいたけど、確認したついでにメモ。

SFDC:すべてのコミュニティ設定のワークスペースリンクにアクセスできなくなったときの対処方法

$
0
0

コミュニティのメンバー追加などの各種設定は「すべてのコミュニティ設定」のワークスペース(管理)リンクで設定ページに移動して行います。
f:id:tyoshikawa1106:20180413152906p:plain


このシステム管理者なら当然アクセスできるよねというリンクは、コミュニティのメンバーでないとアクセスできないルールがあります。
f:id:tyoshikawa1106:20180413152957p:plain


上記ルール自体把握できていませんでしたが、うっかり外すなんて状況普通ないよね...と思っているとこんなケースで発生してしまいました。
1. コミュニティ作成
2. メンバー追加で対象のコミュニティユーザプロファイルを追加
3. 本来なら管理者プロファイルも追加する必要があるのに忘れて保存
4. そのままログアウト
5. 次回ログインして設定の続きをやろうとすると・・・リンクが無い。


はじめ管理者権限があればなんとでもなるのだと思い、権限セットでコミュニティ管理の権限を付与したりしたのですが、アクセスできませんでした。ヘルプサイトを確認するとこの状況になってしまうとAPIでメンバーを登録する必要がある状況になってしまっているとのことです。

API を使用してコミュニティのメンバーシップを更新するには?

Help | Training | Salesforce


ヘルプに手順が記載されていますが、問題解決のためにはコミュニティのNetworkIdを取得する必要あります。コミュニティURLを右クリックして検証すると確認できます。
f:id:tyoshikawa1106:20180413153549p:plain


f:id:tyoshikawa1106:20180413153810p:plain:w300


NetworkIDを取得したらこんな感じでCSVを作成します。
f:id:tyoshikawa1106:20180413154315p:plain


※profileIDは追加したい管理者プロファイルのIDをセットします。詳細ページのURLから取得できます。


CSVの準備ができたらデータローダでINSERTします。対象オブジェクトは[ネットワークメンバーグループ]です。
f:id:tyoshikawa1106:20180413154511p:plain

INSERTの前に

このデータ更新処理を行うには下記の権限が必要です。標準システム管理者プロファイルは値の変更ができないため権限セットで対応します。

コミュニティ管理にアクセスするためには、メンバーに「コミュニティの作成および設定」または「コミュニティの管理」権限も必要です。

正しくCSVを用意できていれば問題なくINSERTが実行されると思います。これでうっかり除外した管理者プロファイルをコミュニティのメンバーに追加できます。ワークスペースリンクが復活しているはずです。

SFDC:LEXのメッセージ機能が利用できない問題で対応したこと

$
0
0

Salesforce ClassicからLightning Experienceに移行する際にひとつ問題がありました。Chatterのメッセージ機能が利用できない問題です。
f:id:tyoshikawa1106:20180414175245p:plain


「メッセージ機能ですか?Salesforceではサポートを終了しました。そういうものなんです。」で押し通そうと思っていたのですが、GitHubに公開されている+Messageを使わせてもらうことで解決しました。



Lightning Experienceにはユーティリティバーというどのページからもアクセスできる機能が利用できます。これをつかってメッセージ機能にアクセスできるようにしました。

f:id:tyoshikawa1106:20180414175548p:plain

f:id:tyoshikawa1106:20180414175601p:plain


もともとはLightning Expcerienceが公開されるよりも前、Salesforce1モバイルアプリでの利用を想定されているのでLEXでの利用は想定されていません。ただ、非公開パッケージも公開されているので開発環境を用意することは簡単にできる状態でした。


SalesforceはLightning Design SystemというCSSフレームワークを公開してくれています。これを利用すればLEX的な見た目に調整することができそうでした。

Lightning Design System


実際にやってみたのがこちら。
f:id:tyoshikawa1106:20180414180144p:plain

f:id:tyoshikawa1106:20180414180201p:plain


少し強引にやってごまかしたところがありますが (Clickリンクのところなど) ひとまずうまくいきました。LEXでのメッセージ機能はこれで運用してみようと思います。

変更した箇所

変更したのはHTML部分とJSの一部処理だけです。

PlusMessageView.page
<apex:page docType="html-5.0" applyHtmlTag="false" showHeader="false" sidebar="false" standardStylesheets="false" controller="PlusMessageCtrl">
<html lang="ja" data-framework="angularjs" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0"></meta>
    <title>Chatter Message</title>
    <apex:stylesheet value="{!URLFOR($Resource.PlusMessageResource,'css/bootstrap.min.css')}" />
    <apex:slds />
  </head>
  <body ng-app="msgapp" ng-init="userId='{!$User.Id}'; languageLocaleKey='{!languageLocaleKey}'" class="slds-scope">
    <ng-view />
    <!-- conversations.html -->
    <script type="text/ng-template" id="conversations.html">
      <section id="msgapp">
        <div class="slds-text-align--right">
          <button onclick="location.href='#/send/'" class="slds-button slds-button_icon slds-button_icon-border-filled" aria-pressed="false">
            <svg class="slds-button__icon" aria-hidden="true">
              <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{!URLFOR($Asset.SLDS, '/assets/icons/utility-sprite/svg/symbols.svg#new_direct_message')}" />
            </svg>
            <span class="slds-assistive-text">New</span>
          </button>
        </div>
        <div>
          <div ng-show="err!=null" class="slds-m-vertical_small slds-notify slds-notify_alert slds-theme_alert-texture slds-theme_error" role="alert">
            <h2>{{err.message}}</h2>
          </div>
          <div ng-show="loading">
            <div style="height: 6rem;">
              <div role="status" class="slds-spinner slds-spinner_medium">
                <span class="slds-assistive-text">Loading</span>
                <div class="slds-spinner__dot-a"></div>
                <div class="slds-spinner__dot-b"></div>
              </div>
            </div>
          </div>
          <div class="slds-feed">
            <ul class="slds-feed__list">
              <li class="slds-feed__item" ng-repeat="conv in convs.conversations">
                <article class="slds-post">
                  <header class="slds-post__header slds-media">
                    <div class="slds-media__figure">
                      <a href="#/{{conv.id}}" class="slds-avatar slds-avatar_circle slds-avatar_medium">
                        <img src="{{conv.latestMessage.sender.photo.smallPhotoUrl}}" />
                      </a>
                    </div>
                    <div class="slds-media__body">
                      <div class="slds-grid slds-grid_align-spread slds-has-flexi-truncate">
                        <p><a href="#/{{conv.id}}">{{conv.latestMessage.sender.name}}</a></p>
                      </div>
                      <p class="slds-text-body_small"><a href="#/{{conv.id}}" class="slds-text-link_reset">{{conv.latestMessage.sentDate}}</a></p>
                    </div>
                  </header>
                  <div class="slds-post__content slds-text-longform">
                    <p><span ng-bind="conv.latestMessage.body.text" style="white-space: pre-wrap;"/></p>
                  </div>
                  <footer class="slds-post__footer">
                    <div class="slds-text-align--right"><a href="#/{{conv.id}}">Click!</a></div>
                  </footer>
                </article>
              </li>
            </ul>
          </div>
        </div>
      </section>
    </script><!-- conversations.html -->

    <!-- send-message.html -->
    <script type="text/ng-template" id="send-message.html">
      <section id="msgapp">
        <div class="slds-clearfix">
          <div class="slds-clearfix">
            <div class="slds-float_left">
              <button onclick="location.href='#/'" class="slds-button slds-button_icon slds-button_icon-border-filled" aria-pressed="false" title="Like">
                <svg class="slds-button__icon" aria-hidden="true">
                  <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{!URLFOR($Asset.SLDS, '/assets/icons/utility-sprite/svg/symbols.svg#back')}" />
                </svg>
                <span class="slds-assistive-text">Back</span>
              </button>
            </div>
          </div>
        </div>
        <div >
          <div ng-show="err!=null" class="slds-m-vertical_small slds-notify slds-notify_alert slds-theme_alert-texture slds-theme_error" role="alert">
            <h2>{{err.message}}</h2>
          </div>
          <div class="slds-m-top--small">
            <textarea name="message" ng-model="message" class="slds-textarea" placeholder="{{ 'MESSAGE' | translate }}"></textarea>
            <div class="input-group-btn"><button type="button" class="slds-button slds-button_brand" ng-click="sendMessage()" translate="SEND">Send</button></div>
          </div>
          <div ng-show="loading">
            <div style="height: 6rem;">
              <div role="status" class="slds-spinner slds-spinner_medium">
                <span class="slds-assistive-text">Loading</span>
                <div class="slds-spinner__dot-a"></div>
                <div class="slds-spinner__dot-b"></div>
              </div>
            </div>
          </div>
          <div style="padding-top: 14px">
            <ul class="list-group">
              <li class="list-group-item list-group-item-info">
                <span translate="RECIPIENTS">Recipients</span>
                <span style="padding-left: 14px;">
                  <button ng-click="openSearchUsers()" ng-show="members.length<9" class="slds-button slds-button_icon slds-button_icon-border-filled" aria-pressed="false">
                    <svg class="slds-button__icon" aria-hidden="true">
                      <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{!URLFOR($Asset.SLDS, '/assets/icons/utility-sprite/svg/symbols.svg#adduser')}" />
                    </svg>
                    <span class="slds-assistive-text">Add</span>
                  </button>
                </span>
            </li>
              <li class="list-group-item" ng-show="members.length==0" translate="NO_RECIPIENTS_MESSAGE">Add Recipients</li>
              <li class="list-group-item" ng-repeat="member in members">
                <div class="slds-size_3-of-4">
                  <div class="slds-media">
                    <div class="slds-media__figure">
                      <span class="slds-avatar slds-avatar_large">
                        <img src="{{member.photo.smallPhotoUrl}}" />
                      </span>
                    </div>
                    <div class="slds-media__body">
                      <div class="name">{{member.name}}</div>
                      <div class="title">{{member.title}}</div>
                    </div>
                  </div>
                </div>
              </li>
            </ul>
          </div>
        </div>
      </section>
    </script><!-- send-message.html -->

    <!-- search-users-dialog.html -->
    <script type="text/ng-template" id="search-user-dialog.html">
      <div class="modal-header">
        <div class="input-group">
          <span class="input-group-addon">@</span>
          <input type="text" name="query" ng-model="searchUsers.query" class="form-control" placeholder="{{ 'RECIPIENTS' | translate }}" x-webkit-speech lang="ja"/>
        </div>
      </div>
      <div class="modal-body">
        <div class="alert alert-danger" ng-show="errDialog!=null">{{errDialog.message}}</div>
        <div ng-show="loadingDialog">
          <div style="height: 6rem;">
            <div role="status" class="slds-spinner slds-spinner_medium">
              <span class="slds-assistive-text">Loading</span>
              <div class="slds-spinner__dot-a"></div>
              <div class="slds-spinner__dot-b"></div>
            </div>
          </div>
        </div>
        <form role="form">
          <div class="list-group" ng-hide="loadingDialog">
            <div class="list-group-item" ng-show="users.length==0" translate="NO_MATCH_USER_MESSAGE">No match user</div>
            <a class="list-group-item" ng-repeat="user in users" ng-click="addUser(user)">
              <div class="slds-size_3-of-4">
                <div class="slds-media">
                  <div class="slds-media__figure">
                    <span class="slds-avatar slds-avatar_large">
                      <img src="{{user.photo.smallPhotoUrl}}" />
                    </span>
                  </div>
                  <div class="slds-media__body">
                    <div class="name">{{user.name}}</div>
                    <div class="title">{{user.title}}</div>
                  </div>
                </div>
              </div>
            </a>
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="slds-button slds-button_neutral" ng-click="$close()" translate="CLOSE">Close</button>
      </div>
    </script><!-- search-users-dialog.html -->

    <!-- messages.html -->
    <script type="text/ng-template" id="messages.html">
      <section id="msgapp">
        <div class="slds-clearfix">
          <div class="slds-clearfix">
            <div class="slds-float_left">
              <button onclick="location.href='#/'" class="slds-button slds-button_icon slds-button_icon-border-filled" aria-pressed="false" title="Like">
                <svg class="slds-button__icon" aria-hidden="true">
                  <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{!URLFOR($Asset.SLDS, '/assets/icons/utility-sprite/svg/symbols.svg#back')}" />
                </svg>
                <span class="slds-assistive-text">Back</span>
              </button>
            </div>
            <div class="slds-float_right">
              <button ng-click="openUsersDialog()" class="slds-button slds-button_icon slds-button_icon-border-filled" aria-pressed="false" title="Like">
                <svg class="slds-button__icon" aria-hidden="true">
                  <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{!URLFOR($Asset.SLDS, '/assets/icons/utility-sprite/svg/symbols.svg#user')}" />
                </svg>
                <span class="slds-assistive-text">Chat Member</span>
              </button>
            </div>
          </div>
        </div>
        <div>
          <div ng-show="err!=null" class="slds-m-vertical_small slds-notify slds-notify_alert slds-theme_alert-texture slds-theme_error" role="alert">
            <h2>{{err.message}}</h2>
          </div>
          <div class="slds-m-top--small">
            <textarea name="message" ng-model="message" class="slds-textarea" placeholder="{{ 'MESSAGE' | translate }}" rows="3"></textarea>
            <div class="input-group-btn"><button type="button" class="slds-button slds-button_brand" ng-click="replyToMessage()" translate="SEND">Send</button></div>
          </div>
          <div ng-show="loading">
            <div style="height: 6rem;">
              <div role="status" class="slds-spinner slds-spinner_medium">
                <span class="slds-assistive-text">Loading</span>
                <div class="slds-spinner__dot-a"></div>
                <div class="slds-spinner__dot-b"></div>
              </div>
            </div>
          </div>
          <div class="slds-feed">
            <ul class="slds-feed__list" ng-hide="loading">
              <li class="slds-feed__item" ng-repeat="msg in msgs.messages.messages">
                <article class="slds-post">
                  <header class="slds-post__header slds-media">
                    <div class="slds-media__figure">
                      <a class="slds-avatar slds-avatar_circle slds-avatar_medium">
                        <img src="{{msg.sender.photo.smallPhotoUrl}}" />
                      </a>
                    </div>
                    <div class="slds-media__body">
                      <div class="slds-grid slds-grid_align-spread slds-has-flexi-truncate">
                        <p><a>{{msg.sender.name}}</a></p>
                      </div>
                      <p class="slds-text-body_small"><a class="slds-text-link_reset">{{msg.sentDate}}</a></p>
                    </div>
                  </header>
                  <div class="slds-post__content slds-text-longform">
                    <p><span ng-bind="msg.body.text" style="white-space: pre-wrap;"/></p>
                  </div>
                </article>
              </li>
            </ul>
          </div>
        </div>
      </section>
    </script><!-- messages.html -->

    <!-- users-dialog.html -->
    <script type="text/ng-template" id="users-dialog.html">
      <div class="modal-header" translate="MEMBER">
        Member
      </div>
      <div class="modal-body">
        <ul class="list-group">
          <li class="list-group-item" ng-repeat="member in msgs.members">
            <div class="slds-size_3-of-4">
              <div class="slds-media">
                <div class="slds-media__figure">
                  <span class="slds-avatar slds-avatar_large">
                    <img src="{{member.photo.smallPhotoUrl}}" />
                  </span>
                </div>
                <div class="slds-media__body">
                  <div class="name">{{member.name}}</div>
                  <div class="title">{{member.title}}</div>
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="modal-footer">
        <button type="button" class="slds-button slds-button_neutral" ng-click="$close()" translate="CLOSE">Close</button>
      </div>
    </script><!-- susers-dialog.html -->


    <!-- waiting-dialog.html -->
    <script type="text/ng-template" id="waiting-dialog.html">
      <div class="modal-header" translate="SENDING_MESSAGE">
        Sending...
      </div>
      <div class="modal-body">
        <div style="height: 6rem;">
          <div role="status" class="slds-spinner slds-spinner_medium">
            <span class="slds-assistive-text">Loading</span>
            <div class="slds-spinner__dot-a"></div>
            <div class="slds-spinner__dot-b"></div>
          </div>
        </div>
      </div>
    </script><!-- waiting-dialog.html -->

    <apex:includeScript value="{!URLFOR($Resource.PlusMessageResource, 'js/angular.min.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageResource, 'js/angular-route.min.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageResource, 'js/angular-translate.min.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageResource, 'js/ui-bootstrap-tpls-0.10.0.min.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageResource, 'js/jquery-2.1.0.min.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageResource, 'js/bootstrap.min.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageJS, 'app.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageJS, 'controllers/messageCtrl.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.PlusMessageJS, 'services/messageService.js')}" />
  </body>
</html>
</apex:page>


JSの方は日本時間に調整したいところがあったので他で実装されていた処理をコピペする形でちょっと手を入れました。

messageService.js

f:id:tyoshikawa1106:20180414180627p:plain


ということでGitHubに公開されている+MessageのおかげでLightning Experienceにメッセージ機能を表示することができました。メッセージ通知の機能とかの要望がくるかもしれませんが、おそらく「メールで気づいてください」で押し通せると思います。いつか標準でサポートされればいいなと思います。(Skype for Salesforceが用意されていましたが試してみたところメッセージ機能とはすこし用途がことなりました。)

管理パッケージ対応

上記で用意したカスタマイズバージョンの+メッセージですが、組織にインストールするときは管理パッケージとしてインストールします。未管理パッケージでも同じ用にインストール可能ですが、管理パッケージにすることで開発時に組織コードに混ざって表示されないようになります。組織に合わせてバンバンカスタマイズしてく場合は未管理パッケージで気軽に開発できるようにした方がいいと思うのですが、通常さわらないのであれば管理パッケージの方が良いと思います。※書いた後にしったのですが、管理パッケージはパートナー組織じゃないとバージョンアップできない落とし穴がありました。

管理パッケージ化するときの注意

管理パッケージにすると組織に名前空間プレフィックスが追加されます。JSからApexクラスにアクセスする処理は下記の規則で修正が必要になります。

<名前空間プレフィックス>.SampleController.geSampleMethod()


先頭に名前空間プレフィックスをつけるだけなので規則がわかればそれほど大変ではないと思います。

追記

Salesforceモバイルアプリでも利用可能ですが、タブの作成が必要になります。またモバイルアプリで表示したときに気づいたのですが、paddingを入れとけばよかったです。

Viewing all 1438 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>