معاينة الروابط باستخدام الشرائح الذكية

توضّح هذه الصفحة كيفية إنشاء إضافة في Google Workspace تتيح لمستخدمي "مستندات Google" و"جداول بيانات Google" و"العروض التقديمية من Google" معاينة روابط من خدمة تابعة لجهة خارجية.

يمكن أن ترصد إضافة Google Workspace روابط خدمتك وتطالب المستخدمين بمعاينتها. يمكنك ضبط إحدى التكميلات لمعاينة أنماط عناوين URL متعددة، مثل الروابط التي تؤدي إلى طلبات الدعم والعملاء المحتملين والملفات الشخصية للموظفين.

كيفية معاينة المستخدمين للروابط

لمعاينة الروابط، يتفاعل المستخدمون مع الشرائح الذكية والبطاقات.

معاينة المستخدم لبطاقة

عندما يكتب المستخدمون عنوان URL أو يلصقونه في مستند أو جدول بيانات، تطلب منهما "مستندات Google" أو "جداول بيانات Google" استبدال الرابط بشريحة ذكية. تعرِض الشريحة الذكية رمزًا وعنوانًا قصيرًا أو وصفًا لمحتوى الرابط. عندما يمرّر المستخدم مؤشر الماوس فوق الشريحة، تظهر له واجهة بطاقة تعرض معاينة لمعلومات إضافية عن الملف أو الرابط.

يوضّح الفيديو التالي كيفية تحويل مستخدم رابط إلى شريحة ذكية واطلاعه على بطاقة:

كيفية معاينة المستخدمين للروابط في "العروض التقديمية من Google"

لا تتوفّر الشرائح الذكية التابعة لجهات خارجية لمعاينات الروابط في العروض التقديمية. عندما يكتب المستخدمون عنوان URL أو يلصقونه في عرض تقديمي، تطلب منهم "العروض التقديمية من Google" استبدال الرابط بعنوانه كأحد النصوص المرتبطة بدلاً من شريحة. عندما يمرّر المستخدِم مؤشّر الماوس فوق عنوان الرابط، تظهر له واجهة بطاقة تعرض معاينة للمعلومات المتعلّقة بالرابط.

توضِّح الصورة التالية كيفية عرض معاينة الرابط في العروض التقديمية:

مثال لمعاينة الرابط في "العروض التقديمية من Google"

المتطلبات الأساسية

برمجة تطبيقات

Node.js

Python

Java

اختياري: إعداد المصادقة مع خدمة تابعة لجهة خارجية

إذا كانت الإضافة تتصل بخدمة تتطلّب تفويضًا، على المستخدمين مصادقة الخدمة لمعاينة الروابط. ويعني ذلك أنّه عندما يلصق المستخدمون رابطًا من خدمتك في ملف "مستندات Google" أو "جداول بيانات Google" أو "العروض التقديمية من Google" للمرة الأولى، يجب أن تطلب الإضافة من المستخدمين منح الإذن.

لإعداد خدمة OAuth أو طلب تفويض مخصّص، اطّلِع على مقالة ربط تكمِّلة بخدمة تابعة لجهة خارجية.

يوضّح هذا القسم كيفية إعداد معاينات الروابط لإضافة Chrome، والتي تتضمّن الخطوات التالية:

  1. ضبط معاينات الروابط في بيان الإضافة
  2. أنشئ واجهة الشريحة الذكية والبطاقة للروابط.

ضبط معاينات الروابط

لضبط معاينات الروابط، حدِّد الأقسام والحقول التالية في بيان الإضافة:

  1. ضمن القسم addOns، أضِف الحقل docs لتوسيع "مستندات Google"، وحقل sheets لتوسيع "جداول بيانات Google"، وحقل slides لتوسيع "العروض التقديمية من Google".
  2. في كل حقل، نفِّذ عامل تشغيل linkPreviewTriggers الذي يتضمّن runFunction (يمكنك تحديد هذه الدالة في القسم التالي، إنشاء الشريحة والبطاقة الذكية).

    للتعرّف على الحقول التي يمكنك تحديدها في linkPreviewTriggers العامل المشغِّل، اطّلِع على المستندات المرجعية لملفات بيان Apps Script أو موارد النشر لوقت التشغيل الآخر.

  3. في الحقل oauthScopes، أضِف النطاق https://www.googleapis.com/auth/workspace.linkpreview لكي يتمكّن المستخدمون من تفويض الإضافة لمعاينة الروابط بالنيابة عنهم.

على سبيل المثال، اطّلِع على قسمَي oauthScopes وaddons فيملف الادّعاء التالي الذي يضبط معاينات الروابط لخدمة طلب الدعم.

{
  "oauthScopes": [
    "https://www.googleapis.com/auth/workspace.linkpreview"
  ],
  "addOns": {
    "common": {
      "name": "Preview support cases",
      "logoUrl": "https://www.example.com/images/company-logo.png",
      "layoutProperties": {
        "primaryColor": "#dd4b39"
      }
    },
    "docs": {
      "linkPreviewTriggers": [
        {
          "runFunction": "caseLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "logoUrl": "https://www.example.com/images/support-icon.png",
          "localizedLabelText": {
            "es": "Caso de soporte"
          }
        }
      ]
    },
    "sheets": {
      "linkPreviewTriggers": [
        {
          "runFunction": "caseLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "logoUrl": "https://www.example.com/images/support-icon.png",
          "localizedLabelText": {
            "es": "Caso de soporte"
          }
        }
      ]
    },
    "slides": {
      "linkPreviewTriggers": [
        {
          "runFunction": "caseLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "logoUrl": "https://www.example.com/images/support-icon.png",
          "localizedLabelText": {
            "es": "Caso de soporte"
          }
        }
      ]
    }
  }
}

في المثال، تعرض إضافة Google Workspace معاينة للروابط الخاصة بخدمات طلبات الدعم في الشركة. تحدِّد الإضافة ثلاثة نماذج لعناوين URL بهدف معاينة الروابط. عندما يتطابق رابط مع أحد أنماط عناوين URL، تنشئ دالة callback caseLinkPreview بطاقة وشريحة ذكية في "مستندات Google" أو "جداول بيانات Google" أو "العروض التقديمية من Google"، ثم تستبدل عنوان URL بعنوان الرابط.

إنشاء الشريحة الذكية والبطاقة

لعرض شريحة ذكية وبطاقة لرابط، يجب تنفيذ أي وظائف حدّدتها في عنصر linkPreviewTriggers.

عندما يتفاعل مستخدم مع رابط يتطابق مع نمط عنوان URL محدّد، يتم تنشيط عامل التفعيل linkPreviewTriggers وتُمرِّر وظيفة الاستدعاء العنصر EDITOR_NAME.matchedUrl.url للحدث كوسيطة. يمكنك استخدام ملف محتوى كائن الحدث هذا لإنشاء الشريحة الذكية والبطاقة الخاصة بمعاينة الرابط.

على سبيل المثال، إذا معاينَى أحد المستخدِمين الرابط https://www.example.com/cases/123456 في "مستندات Google"، يتم عرض الحِزمة التالية للحدث:

JSON

{
  "docs": {
    "matchedUrl": {
        "url": "https://www.example.com/support/cases/123456"
    }
  }
}

لإنشاء واجهة البطاقة، يمكنك استخدام التطبيقات المصغّرة لعرض معلومات عن الرابط. يمكنك أيضًا إنشاء إجراءات تتيح للمستخدمين فتح الرابط أو تعديل محتوياته. للحصول على قائمة بالتطبيقات المصغّرة والإجراءات المتاحة، اطّلِع على المكونات المتوافقة لبطاقات المعاينة.

لإنشاء الشريحة الذكية والبطاقة لمعاينة الرابط:

  1. نفِّذ الدالة التي حدّدتها في القسم linkPreviewTriggers من بيان الإضافة:
    1. يجب أن تقبل الدالة عنصر حدث يحتوي على EDITOR_NAME.matchedUrl.url كوسيطة وأن تعرِض عنصر Card واحدًا.
    2. إذا كانت خدمتك تتطلّب الحصول على تفويض، يجب أن تتم أيضًا استدعاء عملية التفويض في الدالة.
  2. لكل بطاقة معاينة، نفِّذ أي دوالّ استدعاء توفّر تفاعلًا مع التطبيقات المصغّرة للواجهة. على سبيل المثال، إذا أدرجت زرًا يعرض العبارة "عرض الرابط"، يمكنك إنشاء إجراء يحدِّد دالة callback لفتح الرابط في نافذة جديدة. لمزيد من المعلومات عن التفاعلات مع التطبيقات المصغّرة، اطّلِع على الإجراءات الإضافية.

تنشئ التعليمة البرمجية التالية دالة ردّ الاتصال caseLinkPreview لتطبيق Docs:

برمجة تطبيقات

apps-script/3p-resources/3p-resources.gs
/**
* Entry point for a support case link preview.
*
* @param {!Object} event The event object.
* @return {!Card} The resulting preview link card.
*/
function caseLinkPreview(event) {

  // If the event object URL matches a specified pattern for support case links.
  if (event.docs.matchedUrl.url) {

    // Uses the event object to parse the URL and identify the case details.
    const caseDetails = parseQuery(event.docs.matchedUrl.url);

    // Builds a preview card with the case name, and description
    const caseHeader = CardService.newCardHeader()
      .setTitle(`Case ${caseDetails["name"][0]}`);
    const caseDescription = CardService.newTextParagraph()
      .setText(caseDetails["description"][0]);

    // Returns the card.
    // Uses the text from the card's header for the title of the smart chip.
    return CardService.newCardBuilder()
      .setHeader(caseHeader)
      .addSection(CardService.newCardSection().addWidget(caseDescription))
      .build();
  }
}

/**
* Extracts the URL parameters from the given URL.
*
* @param {!string} url The URL to parse.
* @return {!Map} A map with the extracted URL parameters.
*/
function parseQuery(url) {
  const query = url.split("?")[1];
  if (query) {
    return query.split("&")
    .reduce(function(o, e) {
      var temp = e.split("=");
      var key = temp[0].trim();
      var value = temp[1].trim();
      value = isNaN(value) ? value : Number(value);
      if (o[key]) {
        o[key].push(value);
      } else {
        o[key] = [value];
      }
      return o;
    }, {});
  }
  return null;
}

Node.js

node/3p-resources/index.js
/**
 * 
 * A support case link preview.
 *
 * @param {!URL} url The event object.
 * @return {!Card} The resulting preview link card.
 */
function caseLinkPreview(url) {
  // Builds a preview card with the case name, and description
  // Uses the text from the card's header for the title of the smart chip.
  // Parses the URL and identify the case details.
  const name = `Case ${url.searchParams.get("name")}`;
  return {
    action: {
      linkPreview: {
        title: name,
        previewCard: {
          header: {
            title: name
          },
          sections: [{
            widgets: [{
              textParagraph: {
                text: url.searchParams.get("description")
              }
            }]
          }]
        }
      }
    }
  };
}

Python

python/3p-resources/create_link_preview/main.py
def case_link_preview(url):
    """A support case link preview.
    Args:
      url: A matching URL.
    Returns:
      The resulting preview link card.
    """

    # Parses the URL and identify the case details.
    query_string = parse_qs(url.query)
    name = f'Case {query_string["name"][0]}'
    # Uses the text from the card's header for the title of the smart chip.
    return {
        "action": {
            "linkPreview": {
                "title": name,
                "previewCard": {
                    "header": {
                        "title": name
                    },
                    "sections": [{
                        "widgets": [{
                            "textParagraph": {
                                "text": query_string["description"][0]
                            }
                        }]
                    }],
                }
            }
        }
    }

Java

java/3p-resources/src/main/java/CreateLinkPreview.java
/**
 * A support case link preview.
 *
 * @param url A matching URL.
 * @return The resulting preview link card.
 */
JsonObject caseLinkPreview(URL url) throws UnsupportedEncodingException {
  // Parses the URL and identify the case details.
  Map<String, String> caseDetails = new HashMap<String, String>();
  for (String pair : url.getQuery().split("&")) {
      caseDetails.put(URLDecoder.decode(pair.split("=")[0], "UTF-8"), URLDecoder.decode(pair.split("=")[1], "UTF-8"));
  }

  // Builds a preview card with the case name, and description
  // Uses the text from the card's header for the title of the smart chip.
  JsonObject cardHeader = new JsonObject();
  String caseName = String.format("Case %s", caseDetails.get("name"));
  cardHeader.add("title", new JsonPrimitive(caseName));

  JsonObject textParagraph = new JsonObject();
  textParagraph.add("text", new JsonPrimitive(caseDetails.get("description")));

  JsonObject widget = new JsonObject();
  widget.add("textParagraph", textParagraph);

  JsonArray widgets = new JsonArray();
  widgets.add(widget);

  JsonObject section = new JsonObject();
  section.add("widgets", widgets);

  JsonArray sections = new JsonArray();
  sections.add(section);

  JsonObject previewCard = new JsonObject();
  previewCard.add("header", cardHeader);
  previewCard.add("sections", sections);

  JsonObject linkPreview = new JsonObject();
  linkPreview.add("title", new JsonPrimitive(caseName));
  linkPreview.add("previewCard", previewCard);

  JsonObject action = new JsonObject();
  action.add("linkPreview", linkPreview);

  JsonObject renderActions = new JsonObject();
  renderActions.add("action", action);

  return renderActions;
}

المكوّنات المتوافقة لبطاقات المعاينة

تتيح إضافات Google Workspace استخدام التطبيقات المصغّرة والإجراءات التالية لعرض معاينة الرابط بطاقات:

برمجة تطبيقات

حقل خدمة البطاقة النوع
TextParagraph أداة
DecoratedText أداة
Image أداة
IconImage أداة
ButtonSet أداة
TextButton أداة
ImageButton أداة
Grid أداة
Divider أداة
OpenLink الإجراء
Navigation الإجراء
: لا تتوفّر سوى طريقة updateCard.

JSON

حقل البطاقة (google.apps.card.v1) النوع
TextParagraph أداة
DecoratedText أداة
Image أداة
Icon أداة
ButtonList أداة
Button أداة
Grid أداة
Divider أداة
OpenLink الإجراء
Navigation الإجراء
: لا تتوفّر سوى الطريقة updateCard.

مثال كامل: إضافة طلب الحصول على الدعم

يعرض المثال التالي إضافة Google Workspace تعرض معاينة للروابط التي تؤدي إلى طلبات الحصول على الدعم في شركة معيّنة في "مستندات Google".

ينفِّذ المثال ما يلي:

  • معاينات الروابط التي تؤدي إلى طلبات الحصول على الدعم، مثل https://www.example.com/support/cases/1234 تعرض الشريحة الذكية رمزًا للدعم، وتشمل بطاقة المعاينة رقم تعريف الطلب ووصفًا.
  • إذا تم ضبط لغة المستخدم على الإسبانية، تُحوِّل الشريحة الذكية labelText إلى الإسبانية.

البيان

برمجة تطبيقات

apps-script/3p-resources/appsscript.json
{
  "timeZone": "America/New_York",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/workspace.linkpreview",
    "https://www.googleapis.com/auth/workspace.linkcreate"
  ],
  "addOns": {
    "common": {
      "name": "Manage support cases",
      "logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png",
      "layoutProperties": {
        "primaryColor": "#dd4b39"
      }
    },
    "docs": {
      "linkPreviewTriggers": [
        {
          "runFunction": "caseLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "localizedLabelText": {
            "es": "Caso de soporte"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png"
        }
      ],
      "createActionTriggers": [
        {
          "id": "createCase",
          "labelText": "Create support case",
          "localizedLabelText": {
            "es": "Crear caso de soporte"
          },
          "runFunction": "createCaseInputCard",
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png"
        }
      ]
    }
  }
}

JSON

{
  "oauthScopes": [
    "https://www.googleapis.com/auth/workspace.linkpreview"
  ],
  "addOns": {
    "common": {
      "name": "Preview support cases",
      "logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png",
      "layoutProperties": {
        "primaryColor": "#dd4b39"
      }
    },
    "docs": {
      "linkPreviewTriggers": [
        {
          "runFunction": "URL",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "localizedLabelText": {
            "es": "Caso de soporte"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png"
        }
      ]
    }
  }
}

الرمز

برمجة تطبيقات

apps-script/3p-resources/3p-resources.gs
/**
* Entry point for a support case link preview.
*
* @param {!Object} event The event object.
* @return {!Card} The resulting preview link card.
*/
function caseLinkPreview(event) {

  // If the event object URL matches a specified pattern for support case links.
  if (event.docs.matchedUrl.url) {

    // Uses the event object to parse the URL and identify the case details.
    const caseDetails = parseQuery(event.docs.matchedUrl.url);

    // Builds a preview card with the case name, and description
    const caseHeader = CardService.newCardHeader()
      .setTitle(`Case ${caseDetails["name"][0]}`);
    const caseDescription = CardService.newTextParagraph()
      .setText(caseDetails["description"][0]);

    // Returns the card.
    // Uses the text from the card's header for the title of the smart chip.
    return CardService.newCardBuilder()
      .setHeader(caseHeader)
      .addSection(CardService.newCardSection().addWidget(caseDescription))
      .build();
  }
}

/**
* Extracts the URL parameters from the given URL.
*
* @param {!string} url The URL to parse.
* @return {!Map} A map with the extracted URL parameters.
*/
function parseQuery(url) {
  const query = url.split("?")[1];
  if (query) {
    return query.split("&")
    .reduce(function(o, e) {
      var temp = e.split("=");
      var key = temp[0].trim();
      var value = temp[1].trim();
      value = isNaN(value) ? value : Number(value);
      if (o[key]) {
        o[key].push(value);
      } else {
        o[key] = [value];
      }
      return o;
    }, {});
  }
  return null;
}

Node.js

node/3p-resources/index.js
/**
 * Responds to any HTTP request related to link previews.
 *
 * @param {Object} req An HTTP request context.
 * @param {Object} res An HTTP response context.
 */
exports.createLinkPreview = (req, res) => {
  const event = req.body;
  if (event.docs.matchedUrl.url) {
    const url = event.docs.matchedUrl.url;
    const parsedUrl = new URL(url);
    // If the event object URL matches a specified pattern for preview links.
    if (parsedUrl.hostname === 'example.com') {
      if (parsedUrl.pathname.startsWith('/support/cases/')) {
        return res.json(caseLinkPreview(parsedUrl));
      }
    }
  }
};


/**
 * 
 * A support case link preview.
 *
 * @param {!URL} url The event object.
 * @return {!Card} The resulting preview link card.
 */
function caseLinkPreview(url) {
  // Builds a preview card with the case name, and description
  // Uses the text from the card's header for the title of the smart chip.
  // Parses the URL and identify the case details.
  const name = `Case ${url.searchParams.get("name")}`;
  return {
    action: {
      linkPreview: {
        title: name,
        previewCard: {
          header: {
            title: name
          },
          sections: [{
            widgets: [{
              textParagraph: {
                text: url.searchParams.get("description")
              }
            }]
          }]
        }
      }
    }
  };
}

Python

python/3p-resources/create_link_preview/main.py
from typing import Any, Mapping
from urllib.parse import urlparse, parse_qs

import flask
import functions_framework


@functions_framework.http
def create_link_preview(req: flask.Request):
    """Responds to any HTTP request related to link previews.
    Args:
      req: An HTTP request context.
    Returns:
      An HTTP response context.
    """
    event = req.get_json(silent=True)
    if event["docs"]["matchedUrl"]["url"]:
        url = event["docs"]["matchedUrl"]["url"]
        parsed_url = urlparse(url)
        # If the event object URL matches a specified pattern for preview links.
        if parsed_url.hostname == "example.com":
            if parsed_url.path.startswith("/support/cases/"):
                return case_link_preview(parsed_url)

    return {}




def case_link_preview(url):
    """A support case link preview.
    Args:
      url: A matching URL.
    Returns:
      The resulting preview link card.
    """

    # Parses the URL and identify the case details.
    query_string = parse_qs(url.query)
    name = f'Case {query_string["name"][0]}'
    # Uses the text from the card's header for the title of the smart chip.
    return {
        "action": {
            "linkPreview": {
                "title": name,
                "previewCard": {
                    "header": {
                        "title": name
                    },
                    "sections": [{
                        "widgets": [{
                            "textParagraph": {
                                "text": query_string["description"][0]
                            }
                        }]
                    }],
                }
            }
        }
    }

Java

java/3p-resources/src/main/java/CreateLinkPreview.java
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

public class CreateLinkPreview implements HttpFunction {
  private static final Gson gson = new Gson();

  /**
   * Responds to any HTTP request related to link previews.
   *
   * @param request An HTTP request context.
   * @param response An HTTP response context.
   */
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonObject event = gson.fromJson(request.getReader(), JsonObject.class);
    String url = event.getAsJsonObject("docs")
        .getAsJsonObject("matchedUrl")
        .get("url")
        .getAsString();
    URL parsedURL = new URL(url);
    // If the event object URL matches a specified pattern for preview links.
    if ("example.com".equals(parsedURL.getHost())) {
      if (parsedURL.getPath().startsWith("/support/cases/")) {
        response.getWriter().write(gson.toJson(caseLinkPreview(parsedURL)));
        return;
      }
    }

    response.getWriter().write("{}");
  }


  /**
   * A support case link preview.
   *
   * @param url A matching URL.
   * @return The resulting preview link card.
   */
  JsonObject caseLinkPreview(URL url) throws UnsupportedEncodingException {
    // Parses the URL and identify the case details.
    Map<String, String> caseDetails = new HashMap<String, String>();
    for (String pair : url.getQuery().split("&")) {
        caseDetails.put(URLDecoder.decode(pair.split("=")[0], "UTF-8"), URLDecoder.decode(pair.split("=")[1], "UTF-8"));
    }

    // Builds a preview card with the case name, and description
    // Uses the text from the card's header for the title of the smart chip.
    JsonObject cardHeader = new JsonObject();
    String caseName = String.format("Case %s", caseDetails.get("name"));
    cardHeader.add("title", new JsonPrimitive(caseName));

    JsonObject textParagraph = new JsonObject();
    textParagraph.add("text", new JsonPrimitive(caseDetails.get("description")));

    JsonObject widget = new JsonObject();
    widget.add("textParagraph", textParagraph);

    JsonArray widgets = new JsonArray();
    widgets.add(widget);

    JsonObject section = new JsonObject();
    section.add("widgets", widgets);

    JsonArray sections = new JsonArray();
    sections.add(section);

    JsonObject previewCard = new JsonObject();
    previewCard.add("header", cardHeader);
    previewCard.add("sections", sections);

    JsonObject linkPreview = new JsonObject();
    linkPreview.add("title", new JsonPrimitive(caseName));
    linkPreview.add("previewCard", previewCard);

    JsonObject action = new JsonObject();
    action.add("linkPreview", linkPreview);

    JsonObject renderActions = new JsonObject();
    renderActions.add("action", action);

    return renderActions;
  }

}