Salesforce サービスコンソールの習得:LWC と Workspace API の開発者向けガイド

背景と応用シーン

Salesforce 開発者として、私たちは常にユーザーの生産性を向上させる方法を模索しています。特に、カスタマーサービスの世界では、エージェントが迅速かつ効率的に顧客の問題を解決できるかどうかが、顧客満足度に直結します。ここで中心的な役割を果たすのが Service Console (サービスコンソール) です。

Service Console は、サポートエージェントが必要なすべての情報とツールを単一の画面に集約するために設計された、タブベースのワークスペースです。従来の Salesforce のナビゲーションとは異なり、複数のレコード(例えば、取引先責任者、ケース、関連ナレッジ記事)をタブやサブタブとして同時に開くことができます。これにより、コンテキストの切り替えに伴う時間的ロスを最小限に抑え、エージェントは顧客との対話に集中できます。

標準機能だけでも非常に強力ですが、ビジネスプロセスが複雑化するにつれて、標準のレイアウトやコンポーネントだけでは対応しきれない要件が出てきます。例えば、以下のような応用シーンが考えられます。

  • ケースに対応中、関連する注文情報を外部システムから API 経由で取得し、ケースのサブタブとして表示したい。
  • 特定のケース種別の場合、関連するトラブルシューティング用のフローを自動的に新しいタブで開きたい。
  • ボタン一つで、現在のケース情報に基づいてナレッジ記事の新規作成画面をサブタブで開き、主要な項目を自動入力したい。

このような高度なカスタマイズを実現するために、Salesforce は開発者向けに強力なツールを提供しています。それが Lightning Web Components (LWC) (Lightning Webコンポーネント) と Lightning Workspace API (Lightning ワークスペース API) です。これらを組み合わせることで、開発者は Service Console の動作をプログラムで制御し、ビジネス要件に完全に合致したユーザー体験を構築することが可能になります。


原理説明

Service Console の動的な振る舞いをプログラムで制御するための核となるのが、Lightning Workspace API です。この API は、コンソール内のタブやサブタブの操作、フォーカスの制御、状態の取得などを JavaScript から行うためのメソッド群を提供します。

現代の Salesforce 開発において、この API を利用する主要な方法は、LWC の lightning/platformWorkspaceApi モジュールを使用することです。このモジュールは、Workspace API の機能を LWC の中で簡単に利用できるように設計されたアダプタです。

主な機能は以下の通りです。

1. タブとサブタブの操作

Workspace API を使用すると、新しいプライマリタブやサブタブを開くことができます。レコードページ、コンポーネント、URL、Visualforce ページなど、様々なコンテンツをタブとして開くことが可能です。これにより、例えば現在のケースレコードのサブタブとして、関連する取引先のレコードページを動的に開くといった操作が実現できます。

  • openTab(): 新しいプライマリタブを開きます。
  • openSubtab(): 現在フォーカスされているプライマリタブのサブタブを開きます。
  • closeTab(): 指定したタブを閉じます。

2. フォーカス制御

複数のタブが開かれている状況で、特定のタブにユーザーの注意を向けさせたい場合があります。Workspace API は、プログラムによって特定のタブにフォーカスを移す機能を提供します。

  • focusTab(): 指定したタブにフォーカスを合わせます。

3. タブ情報の取得

現在開かれているタブや、コンポーネントが配置されているタブに関する情報を取得できます。これにより、コンポーネントは自身のコンテキストを理解し、それに応じた動作を行うことができます。

  • getEnclosingTabId(): コンポーネントが含まれているタブの ID を取得します。これはサブタブを開く際の親タブを指定するために頻繁に使用されます。
  • getAllTabInfo(): 開かれているすべてのタブの情報を取得します。
  • getFocusedTabInfo(): 現在フォーカスされているタブの情報を取得します。

4. タブのリフレッシュ

外部システムの更新やバックグラウンド処理の結果をタブの表示に反映させたい場合、タブ全体をリフレッシュすることができます。

  • refreshTab(): 指定したタブを更新します。

これらの機能を LWC 内から呼び出すことで、Service Console のユーザーインターフェースとユーザー体験を、宣言的な設定の限界を超えて拡張することが可能になります。


示例代码

ここでは、ケースレコードページに配置された LWC から、関連する取引先責任者レコードを新しいサブタブとして開く例を見てみましょう。このコードは Salesforce の公式ドキュメントに基づいています。

まず、LWC の JavaScript ファイルです。lightning/platformWorkspaceApi をインポートし、@wire アダプタを使ってコンポーネントが配置されているタブの ID を取得します。そして、ボタンクリック時に openSubtab() メソッドを呼び出します。

openContactSubtab.js

import { LightningElement, wire, api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import { getRecord } from 'lightning/uiRecordApi';

// Workspace API をインポートします
import {
    getEnclosingTabId,
    openSubtab
} from 'lightning/platformWorkspaceApi';

// ケースオブジェクトから ContactId を取得するためのフィールドを指定
const FIELDS = ['Case.ContactId'];

export default class OpenContactSubtab extends NavigationMixin(LightningElement) {
    // 現在のレコードページのレコードIDを自動的に受け取ります
    @api recordId;

    // ケースの ContactId を格納する変数
    contactId;

    // コンポーネントが配置されているタブのIDを格納する変数
    enclosingTabId;

    // @wire を使用して、現在のタブIDを取得します。
    // このIDは、後でサブタブを開く際の親タブとして使用されます。
    @wire(getEnclosingTabId)
    wiredEnclosingTabId(value) {
        // データが返ってきたら、プロパティに設定します
        if (value.data) {
           this.enclosingTabId = value.data;
        }
        if (value.error) {
            console.error('Error getting enclosing tab id', value.error);
        }
    }

    // @wire を使用して、現在のケースレコードから ContactId を取得します
    @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
    wiredCase({ error, data }) {
        if (data) {
            this.contactId = data.fields.ContactId.value;
        } else if (error) {
            console.error('Error getting case data', error);
        }
    }

    // ボタンがクリックされたときに実行されるハンドラ関数
    async handleOpenSubtab() {
        // ContactId が存在しない場合は処理を中断
        if (!this.contactId) {
            console.warn('ContactId is not available.');
            return;
        }

        // openSubtab メソッドを呼び出して新しいサブタブを開きます
        const { tabId } = await openSubtab({
            parentTabId: this.enclosingTabId, // 親となるタブのID
            recordId: this.contactId, // サブタブで開くレコードのID
            label: 'Contact', // サブタブに表示されるラベル
            focus: true // サブタブを開いた後にフォーカスを合わせるか
        });

        console.log(`Subtab opened with ID: ${tabId}`);
    }
}

openContactSubtab.html

HTML テンプレートは非常にシンプルです。ボタンを一つ配置し、クリックイベントにハンドラを紐付けます。

<template>
    <lightning-card title="Open Contact Subtab" icon-name="standard:contact">
        <div class="slds-p-around_medium">
            <p class="slds-m-bottom_small">
                Click the button to open the related contact in a new subtab.
            </p>
            <!-- 関連する取引先責任者が存在する場合のみボタンを有効化 -->
            <lightning-button
                label="Open Contact"
                onclick={handleOpenSubtab}
                disabled={!contactId}>
            </lightning-button>
        </div>
    </lightning-card>
</template>

openContactSubtab.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>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <objects>
                <object>Case</object>
            </objects>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

このコンポーネントをデプロイし、Lightning アプリケーションビルダーでケースのレコードページに配置すると、「Open Contact」ボタンが表示されます。このボタンをクリックすると、現在のケースタブの隣に、関連する取引先責任者のレコードが新しいサブタブとして開かれます。


注意事項

Workspace API を使用して Service Console をカスタマイズする際には、いくつかの注意点があります。

1. 実行コンテキスト

最も重要な注意点は、Workspace API は Salesforce コンソールアプリケーション内でのみ機能するという点です。標準のナビゲーションを持つアプリケーション(「セールス」アプリなど)のページにこの API を使用するコンポーネントを配置しても、API の呼び出しは失敗します。開発時には、必ず Service Console アプリケーションでテストを行ってください。

2. 権限

プログラムでレコードを開く場合でも、実行ユーザーにはそのレコードやオブジェクトに対する適切なアクセス権(参照権限など)が必要です。権限が不足している場合、タブを開こうとしてもエラーが発生します。

3. エラー処理

openSubtab などの Workspace API メソッドは Promise を返します。これは非同期処理が成功したか失敗したかを扱うためのオブジェクトです。サンプルコードのように async/await を使用するか、.then().catch() ブロックを使用して、API 呼び出しが失敗した場合の処理を適切に記述することが重要です。例えば、存在しないレコードIDでタブを開こうとした場合などにエラーが発生するため、これを捕捉してユーザーにフィードバックを提供すべきです。

4. API のバージョンと互換性

Salesforce はバージョンアップごとに API を拡張・変更することがあります。常に最新のリリースノートを確認し、使用しているメソッドが非推奨になっていないか、新しい便利なメソッドが追加されていないかをチェックする習慣が推奨されます。


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

Service Console は、サポートエージェントの生産性を劇的に向上させる強力なツールです。そして、LWCWorkspace API を活用することで、私たち開発者はその能力をさらに引き出し、特定のビジネスニーズに合わせた、高度にカスタマイズされたユーザー体験を提供することができます。

最後に、Service Console の開発におけるベストプラクティスをいくつか挙げます。

  1. 宣言的アプローチを優先する: コードを書く前に、まず標準機能、クイックアクション、フロー、動的フォームなどで要件を満たせないか検討しましょう。コードによるカスタマイズは、宣言的な方法では実現不可能な場合にのみ採用するべきです。
  2. ユーザー中心の設計: カスタマイズの目的は、エージェントの作業を簡素化し、効率化することです。新しいコンポーネントや機能を追加する際は、それが本当にエージェントのワークフローを改善するのかを常に問いかけてください。
  3. パフォーマンスを考慮する: Console に配置する LWC は、軽量で高速に動作するように設計してください。複雑なデータ処理や多数の API 呼び出しは、非同期で行い、ユーザーインターフェースの応答性を損なわないように注意が必要です。
  4. 一貫性のある UI/UX: Salesforce Lightning Design System (SLDS) (Salesforce Lightning デザインシステム) を活用し、標準コンポーネントと見た目や操作感に一貫性のあるカスタムコンポーネントを構築してください。これにより、ユーザーの学習コストが削減され、スムーズな導入が可能になります。
  5. 徹底的なテスト: さまざまなシナリオ(例:関連レコードが存在しない場合、ユーザー権限が異なる場合)でコンポーネントの動作をテストしてください。特に、コンソールという特殊な環境でのテストは不可欠です。

これらの原則に従うことで、私たちは保守性が高く、ユーザーに愛される強力な Service Console ソリューションを構築できるでしょう。

コメント