Quick Look: Lightning Console API

この記事は[Salesforce Platform Advent Calendar](https://qiita.com/advent-calendar/2017/salesforce-platform)の10日目の記事です．Lightning Experienceにおけるコンソールアプリケーションの紹介と，Lightningコンソールで用いることができるAPIを，ClassicのAPIと比較しながら簡単に紹介します．

## Lightningコンソールアプリケーションについて
Summer '17から，コンソールアプリケーションがLightning Experienceで正式リリースとなりました．Classicとの大きな違いは，Service CloudユーザだけでなくSales Cloudユーザも利用可能になったことでしょう．

<img width="639" alt="sales_console_lightning_cap.png" src="https://qiita-image-store.s3.amazonaws.com/0/184624/97383101-a99b-b2d9-c6fe-214b76b38860.png" align="center">

また，Lightningコンソールでは，分割ビューと呼ばれる折り畳み可能なリストビューコンポーネントが追加され，コンソールアプリケーションの長所である1画面で複数のレコードにアクセスできる機能がますます強化されました．

## LightningコンソールAPIとは
Lightningコンソールアプリケーションで利用できるコンポーネントAPIです．タブ・ユーティリティバー・オムニチャネルコンポーネントをJavaScriptで制御できます．このAPIを用いると例えば，1) ユーティリティバーで顧客検索を行い，2) 検索結果から顧客情報をワークスペースタブとして起動し、3) 新規ケースをサブタブして起動する…等，コンソールアプリケーション内の各機能を連動させたカスタム機能の開発が可能になります．

### APIの利用方法
必要なコンポーネントのインスタンスを作成し，aura:idを割り当ててクライアントサイドコントローラから呼び出します．\<aura:method>と同じですね．

| コンポーネント       |用途|
|:-----------------|:--------------------|
|\<lightning:workspaceAPI> |タブの制御|
|\<lightning:utilityBarAPI>|ユーティリティバーの制御| 
|\<lightning:omniToolkitAPI>|オムニチャネルコンポーネントの制御| 

### 簡単な例 \- サブタブを開く
ワークスペースタブを新規に開き、その上でサブタブを新規に開いてみましょう．

```openSubtab.cmp
<lightning:component>
    <lightning:workspaceAPI aura:id="workspaceAPI" />
    <lightning:button label="Open Tab with Subtab" onclick="{!c.openTabWithSubtab}" />
</lightning:component>
```

```openSubtabController.js
({
    openTabWithSubtab : function(component, event, helper) {
        var workspaceAPI = component.find("workspaceAPI");
        workspaceAPI.openTab({
            url: '#/sObject/5000k000005wDM3AAM/view',
            focus: true
        }).then((response) => {
            workspaceAPI.openSubtab({
                parentTabId: response,
                url: '#/sObject/0030k00000HTKpwAAH/view',
                focus: true
            });
        })
        .catch(function(error) {
            console.log(error);
        });
    }
})
```

このように，Lightning Console APIのメソッドは**引数をJSONで受け取り，Promiseを返します．**比較のためClassicの場合の例を以下に示します．

```openSubtab.vfp
<apex:page>
    <a href="#" onclick="openTabWithSubtab();return false">Open Tab with subtab</a> 
    <apex:includeScript value="/support/console/41.0/integration.js"/>
    <script type="text/javascript">
        function openTabWithSubtab() {
            sforce.console.openPrimaryTab(null, '/0030k00000HTKpwAAH', true, 'Contact',　(primaryTabResult) => {
                if(primaryTabResult.success){
                    sforce.console.openSubtab(primaryTabResult.id, '/5000k000005wDM3AAM', true, 'Case', null,　(subTabResult) => {
                        if(!subTabResult.success){
                            console.log('subtab cannot be opened');
                        }
                    });
                }
            });
        }
    </script>
</apex:page>
```

## Lightningコンソールのイベントを処理する
通常のイベント処理と同一で，\<aura:handler>タグで処理できます．なお，Winter 18'時点ではLightningコンソールAPIではタブ回りのイベントしか提供されてないため注意が必要です．

### 簡単な例 \- タブのフォーカス切り替えイベントを処理する
ワークスペースタブを切り替えた際のイベントを拾ってみましょう．

```handleWorkspaceTabFocused.cmp
<lightning:component>
    <lightning:workspaceAPI aura:id="workspaceAPI" />	
    <aura:handler event="lightning:tabFocused" action="{!c.onTabFocused}"/> 
</aura:component>
```

```handleWorkspaceTabFocused.js
({
    onTabFocused() : function(component, event, helper){
        var previousTabId = event.getParam('previousTabId');
        var focusedTabId = event.getParam('currentTabId');
        //do something
    },
})
```

こちらも比較のため，Classicの場合を示します．ClassicではonFocusedPrimaryTab()メソッドによりイベントをキャッチしていました．

```handlePrimaryTabFocused.vfp
<apex:page>
    <apex:includeScript value="/support/console/41.0/integration.js"/>
    <script type="text/javascript">
        sforce.console.onFocusedPrimaryTab((result) => {
            console.log('Focus changed to a different primary tab. The primary tab ID is:' 
        + result.id + 'and the object Id is:' + result.objectId);
        });
    </script>
</apex:page>
```

----

## Classicからの主要な変更点
個人的に気になったポイントをいくつか紹介します．
### フォーカスされたタブの情報を1つのメソッドでまとめて取得
フォーカスされたタブの情報を取得する場合，Classicでは複数のメソッド([getFocusedPrimaryTabId()](https://developer.salesforce.com/docs/atlas.ja-jp.210.0.api_console.meta/api_console/sforce_api_console_getfocusedprimarytabid.htm)や[getFocusedSubtabObjectId()](https://developer.salesforce.com/docs/atlas.ja-jp.210.0.api_console.meta/api_console/sforce_api_console_getfocusedsubtabobjectid.htm)等)を使い分ける必要がありましたが，Lightningでは[getFocusedTabInfo()](https://developer.salesforce.com/docs/atlas.en-us.api_console.meta/api_console/sforce_api_console_lightning_getFocusedTabInfo.htm)だけで済みます．

```getTabInfoInLightning.js
({
    getFocusedTabInfo : function(component, event, helper) {
        var workspaceAPI = component.find("workspaceAPI");
        workspaceAPI.getFocusedTabInfo().then((response) => {
            console.log(response);
        });
    }
})
```

responseは以下のようになります．isSubtabでワークスペースタブかサブタブかを識別できます．タブIDの命名方式もClassic(scc-pt-0, scc-st-1 等)とは異なっていますね．

```
{ tabId: ctab0,
     pinned: false,
     closeable: true,
     title: "Kosaka Shun",
     icon: "standard:contact",
     iconAlt: "Contact",
     recordId: "0030k00000HTXvLAAX",
     url: "https://yourinstance.lightning.force.com/one/one.app#/sObject/0030k00000HTXvLAAX/view",
     subtabs: [
         {
             tabId: ctab0_1,
             pinned: false,
             closeable": true,
             title: "00001004",
             icon: "standard:case",
             iconAlt: "Case",
             recordId: string,
             url: "https://yourinstance.lightning.force.com/one/one.app#/sObject/5000k000002Wa7MAAS/view",
             isSubtab: true,
             parentTabId: ctab0,
             customTitle: undefined,
             customIcon: undefined,
             customIconAlt: undefined
          },
          { ... }
     ],
     isSubtab: false,
     parentTabId: null,
     customTitle: undefined,
     customIcon: undefined,
     customIconAlt: undefined
}
```

### setTabIcon()でSLDSのアイコンを直接指定可能に
[LightningのsetTabIcon()](https://developer.salesforce.com/docs/atlas.en-us.api_console.meta/api_console/sforce_api_console_lightning_setTabIconURL.htm)は，\<lightning:icon>と同様に，アイコンのキーを指定できるようになりました．Classicでは画像ファイルのパスが必要であり，静的リソースにタブアイコンのPNGファイルを別途アップロードしてそれを用いる等の切ない対応が必要でした…． 

###ユーティリティバーでモーダルビューの切り替えが可能に
[toggleModalMode()](https://developer.salesforce.com/docs/atlas.en-us.api_console.meta/api_console/sforce_api_console_lightning_toggleModalMode.htm)で，ユーティリティバーをモーダルビュー(=表示中のユーティリティバーコンポーネント以外の操作を不可にする)に切り替えることが可能です．しかし，ユーティリティーバーを最小化する際のイベントが提供されていないため，モーダルビュー表示のままユーティリティバーを最小化すると他の操作ができなくなってしまいます…．ということで今のところはあまり使い道が無いかも．

<img src="https://qiita-image-store.s3.amazonaws.com/0/184624/93645ab2-0e05-a6a2-c87c-f19f18d19dd8.gif" width="640" />

## おわりに
LightningコンソールAPIはまだ正式リリースされたばかりで発展途上ではありますが，Lightningコンソールアプリケーションで実現できる機能が急増しているため，APIも今後どんどん便利になっていくものと思います(願望)．ぜひアプリケーション作成時の選択肢としてLightningコンソールを加えてみてはいかがでしょうか．

## 参考
* [Salesforce Console Developer Guide](https://developer.salesforce.com/docs/atlas.ja-jp.api_console.meta/api_console/sforce_api_console.htm) 
* [Lightningコンポーネント開発者ガイド force:utilityBarAPI](https://developer.salesforce.com/docs/atlas.ja-jp.lightning.meta/lightning/aura_compref_force_utilityBarAPI.htm)
* [Lightningコンポーネント開発者ガイド force:workspaceAPI](https://developer.salesforce.com/docs/atlas.ja-jp.lightning.meta/lightning/aura_compref_force_workspaceAPI.htm)

※ 記事執筆時点では，日本語版のLightningコンソールAPIのドキュメントは提供されていせんが，メソッドの一覧程度であれば，Lightningコンポーネント開発者ガイドに日本語の情報があります．