Salesforce Service Consoleのカスタマイズ:Lightning Console JavaScript APIの徹底解説


背景と利用シナリオ

Salesforce Service Console (サービスコンソール) は、顧客サービスの担当者(エージェント)が、迅速かつ効率的に顧客対応を行うために設計された、タブベースのワークスペースです。複数の関連レコードを一つの画面に表示し、コンテキストの切り替えを最小限に抑えることで、エージェントの生産性を劇的に向上させます。標準機能だけでも非常に強力ですが、実際のビジネス要件は多岐にわたり、より高度な自動化や画面連携が求められるケースが少なくありません。

例えば、以下のようなシナリオが考えられます。

  • CTI (Computer Telephony Integration) システムから着信があった際、電話番号に紐づく取引先責任者レコードを自動でサブタブとして開きたい。
  • ケースレコード上で特定の操作を行った後、関連するナレッジ記事や注文履歴をプログラムで自動的に表示させたい。
  • 複雑な業務フローをコンポーネント化し、ユーザーのアクションに応じて特定のタブを閉じたり、更新したりする処理を実装したい。

このような動的な画面制御を実現するために Salesforce が提供しているのが、Lightning Console JavaScript API です。このAPIを利用することで、開発者は Lightning Web Components (LWC) や Aura Components 内から Service Console のタブやワークスペースを直接操作できるようになり、標準機能だけでは実現不可能な、高度にカスタマイズされたユーザーエクスペリエンスを構築することが可能になります。

本記事では、Salesforce 技術アーキテクトの視点から、この Lightning Console JavaScript API の原理を解説し、具体的なコード例を交えながら、その活用方法とベストプラクティスについて詳説します。


原理説明

Lightning Console JavaScript API は、Lightning Experience の Service Console アプリケーション内で実行されるカスタムコンポーネントに対して、コンソールの状態を制御するためのインターフェースを提供します。このAPIは、主に LWC と Aura の2つのプログラミングモデルで利用できますが、現在ではパフォーマンスと開発効率の観点から LWC での利用が推奨されています。

LWC でこの API を利用する場合、lightning/platformWorkspaceApi モジュールをインポートします。このモジュールは、コンソール環境で実行されている場合にのみ機能し、コンソールを操作するための様々なメソッドを公開します。

主要な概念は以下の通りです。

Workspace API

すべての操作の起点となる API です。LWC では lightning/platformWorkspaceApi ワイヤーアダプタを通じてインスタンス化され、これを通じてタブのオープン、クローズ、フォーカスなどのメソッドを呼び出します。このAPIは Promise を返す非同期メソッドが多いため、非同期処理(async/await や .then())の知識が不可欠です。

タブとサブタブ

Service Console は、主要なレコード(例えば取引先)を表示する「プライマリタブ」と、そのプライマリタブに関連するレコード(例えば取引先責任者やケース)を表示する「サブタブ」という階層構造を持っています。API を利用することで、特定のプライマリタブのコンテキスト内で新しいサブタブを開いたり、現在フォーカスされているタブの情報を取得したりすることができます。

主要なメソッド

lightning/platformWorkspaceApi は、コンソール操作のための多彩なメソッドを提供しています。以下に代表的なものを挙げます。

  • openTab(): 新しいプライマリタブを開きます。
  • openSubtab(): 現在フォーカスされているプライマリタブ内に、新しいサブタブを開きます。
  • getFocusedTabInfo(): 現在アクティブなタブ(プライマリまたはサブ)の情報を取得します。タブID、レコードID、URLなどが含まれます。
  • refreshTab(): 指定したタブをリフレッシュし、最新のデータを表示します。
  • closeTab(): 指定したタブを閉じます。
  • setTabLabel(): タブのラベルを動的に変更します。
  • setTabIcon(): タブのアイコンを動的に変更します。

これらのメソッドを組み合わせることで、ユーザーの操作や外部システムのイベントに応じて、コンソール画面を自由自在に制御するロジックを実装できます。


示例代码

ここでは、LWC を使用して Lightning Console JavaScript API を活用する具体的なコード例を2つ紹介します。これらのコードは、Salesforce の公式ドキュメントに基づいています。

例1:レコードページのサブタブを開く

この例では、現在開いているプライマリタブ(例えば、取引先レコード)のコンテキストで、関連する特定のレコード(例えば、取引先責任者)を新しいサブタブとして開く LWC コンポーネントを作成します。

workspaceAPISubtab.html

<template>
    <lightning-card title="Workspace API Subtab Demo" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
            <p>現在のタブのサブタブとして、特定の取引先責任者レコードを開きます。</p>
            <lightning-button
                label="Open Contact Subtab"
                onclick={openContactSubtab}
                variant="brand">
            </lightning-button>
        </div>
    </lightning-card>
</template>

workspaceAPISubtab.js

import { LightningElement, wire } from 'lwc';
import { EnclosingTabId, openSubtab } from 'lightning/platformWorkspaceApi';

export default class WorkspaceAPISubtab extends LightningElement {
    // 現在のコンポーネントが含まれているタブのIDを取得
    @wire(EnclosingTabId) tabId;

    // ボタンクリック時の処理
    async openContactSubtab() {
        // openSubtabメソッドを呼び出し
        // このメソッドは非同期で、成功すると新しいサブタブのIDを返すPromiseを返す
        try {
            const { tabId } = this;
            const subtabId = await openSubtab(tabId, {
                // ここでは特定の取引先責任者レコードIDをハードコード
                // 実際のアプリケーションでは、動的にIDを取得するロジックが必要
                recordId: '003xxxxxxxxxxxxxxx', 
                label: 'Related Contact', // サブタブに表示されるラベル
                focus: true // サブタブを開いた後、自動的にフォーカスを当てる
            });

            // 成功した場合の処理(例:コンソールにログを出力)
            console.log('Subtab opened with ID: ', subtabId);

        } catch (error) {
            // エラーが発生した場合の処理
            console.error('Error opening subtab: ', error);
        }
    }
}

workspaceAPISubtab.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
    </targets>
</LightningComponentBundle>

注釈:openSubtab メソッドの第一引数には、親となるプライマリタブのIDが必要です。@wire(EnclosingTabId) を使用することで、コンポーネントが配置されているタブのIDをリアクティブに取得できます。第二引数には、開きたいページの情報(レコードID、URL、ラベルなど)をオブジェクトとして渡します。

例2:フォーカスされているタブの情報を取得し、リフレッシュする

この例では、現在ユーザーがアクティブにしているタブの情報を取得し、そのタブをリフレッシュする機能を持つコンポーネントを作成します。

workspaceAPIRefresh.html

<template>
    <lightning-card title="Workspace API Focus and Refresh Demo" icon-name="utility:refresh">
        <div class="slds-m-around_medium">
            <p class="slds-m-bottom_small">現在フォーカスされているタブの情報を取得し、リフレッシュします。</p>
            <lightning-button label="Get Focused Tab Info" onclick={getFocusedTab} class="slds-m-right_small"></lightning-button>
            <lightning-button label="Refresh Focused Tab" onclick={refreshFocusedTab} variant="brand"></lightning-button>
            <div if:true={focusedTabInfo} class="slds-m-top_medium">
                <p><b>Tab ID:</b> {focusedTabInfo.tabId}</p>
                <p><b>Page URL:</b> {focusedTabInfo.url}</p>
                <p><b>Page Title:</b> {focusedTabInfo.title}</p>
            </div>
        </div>
    </lightning-card>
</template>

workspaceAPIRefresh.js

import { LightningElement, track } from 'lwc';
import { getFocusedTabInfo, refreshTab } from 'lightning/platformWorkspaceApi';

export default class WorkspaceAPIRefresh extends LightningElement {
    @track focusedTabInfo;

    // フォーカスされているタブ情報を取得するメソッド
    async getFocusedTab() {
        try {
            // getFocusedTabInfoは現在のタブ情報を返すPromiseを返す
            const tabInfo = await getFocusedTabInfo();
            this.focusedTabInfo = tabInfo;
            console.log('Focused tab info:', tabInfo);
        } catch (error) {
            console.error('Error getting focused tab info:', error);
        }
    }

    // フォーカスされているタブをリフレッシュするメソッド
    async refreshFocusedTab() {
        try {
            // まず、現在のタブ情報を取得してタブIDを得る
            const { tabId } = await getFocusedTabInfo();
            
            // refreshTabメソッドで指定したタブIDをリフレッシュ
            // includeAllSubtabsをtrueにすると、関連するサブタブも全てリフレッシュされる
            await refreshTab(tabId, {
                includeAllSubtabs: false,
                label: 'Refreshed' // リフレッシュ中の一時的なラベル
            });
            console.log(`Tab ${tabId} refreshed successfully.`);
        } catch (error) {
            console.error('Error refreshing tab:', error);
        }
    }
}

注釈:getFocusedTabInfo は引数を取らず、呼び出された時点でのアクティブなタブ情報を返します。refreshTab はリフレッシュ対象のタブIDを引数に取ります。このため、リフレッシュ処理を行う前に、まず getFocusedTabInfo で対象のタブIDを取得する必要があります。


注意事項

Lightning Console JavaScript API を利用する際には、いくつかの重要な点に注意する必要があります。

実行コンテキスト

このAPIは、Salesforce Service Console アプリケーション内でのみ機能します。通常の Lightning アプリケーション(標準ナビゲーションスタイル)のページにコンポーネントを配置しても、API は機能せず、エラーが発生します。開発時には、必ずコンソールアプリのコンテキストでテストを行ってください。

権限

API を利用するユーザーは、対象となるコンソールアプリケーションへのアクセス権が必要です。また、API を通じてレコードを開いたり操作したりする場合、そのユーザーは対象オブジェクトやレコードに対する適切な CRUD (Create, Read, Update, Delete) 権限および共有設定を持っている必要があります。

API の制限とパフォーマンス

プログラムによって大量のタブを一度に開くような実装は、ユーザーのブラウザのメモリを圧迫し、パフォーマンスの低下を招く可能性があります。ユーザーエクスペリエンスを損なわないよう、必要最小限のタブを開くように設計することが重要です。また、API の呼び出しは非同期であるため、連続して呼び出す場合には順序制御に注意が必要です。

エラーハンドリング

lightning/platformWorkspaceApi のメソッドは、ほとんどが Promise を返します。これは、操作が成功する場合も失敗する場合もあることを意味します。例えば、存在しないタブIDを閉じようとしたり、コンソール外で API を呼び出したりすると、Promise は reject されます。したがって、コードを実装する際には、必ず try...catch ブロック(async/await を使用する場合)や .catch() 句(Promise チェーンを使用する場合)を用いて、堅牢なエラーハンドリングを組み込む必要があります。


まとめとベストプラクティス

Salesforce Lightning Console JavaScript API は、Service Console の機能を拡張し、エージェントの業務プロセスに最適化された、ダイナミックでインタラクティブなユーザーインターフェースを構築するための強力なツールです。このAPIを効果的に活用することで、開発者は標準機能の枠を超えたソリューションを提供できます。

以下に、本APIを利用する上でのベストプラクティスをまとめます。

  1. LWC を優先的に利用する: 新規開発では、パフォーマンス、最新のWeb標準への準拠、開発体験の観点から、Aura ではなく LWC での実装を選択してください。
  2. コンテキストを意識した設計: コンポーネントがコンソール環境で実行されているかどうかを判定するロジックを組み込むことで、コンソール外でもエラーなく動作する(あるいは代替の動作をする)汎用的なコンポーネントを作成できます。
  3. 非同期処理を正しく理解する: Promise や async/await の仕組みを十分に理解し、API の非同期性を前提としたコードを記述してください。これにより、予期せぬ動作やレースコンディションを防ぐことができます。
  4. ユーザーエクスペリエンスを最優先する: API の力で何でもできますが、エージェントが混乱するような過度な自動化は避けるべきです。本当に生産性向上に寄与する機能は何かを常に考え、シンプルで直感的な操作性を提供することを目標にしてください。
  5. Lightning Message Service (LMS) との連携: コンソール内の異なるコンポーネント間で通信を行いたい場合、Workspace API と LMS を組み合わせることで、疎結合で拡張性の高いアーキテクチャを実現できます。例えば、あるコンポーネントがタブを開き、別のコンポーネントがそのタブが開かれたことを検知して処理を行う、といった連携が可能です。

これらの原理とベストプラクティスを理解し、適切に Lightning Console JavaScript API を活用することで、Service Console を真にビジネスニーズに合致した強力なプラットフォームへと昇華させることができるでしょう。

コメント