Linkvorschau mit Smartchips

Auf dieser Seite wird beschrieben, wie Sie ein Google Workspace-Add-on erstellen, mit dem Nutzer von Google Docs, Google Tabellen und Google Präsentationen Links von Drittanbieterdiensten in der Vorschau ansehen können.

Ein Google Workspace-Add-on kann die Links Ihres Dienstes erkennen und Nutzer auffordern, eine Vorschau aufzurufen. Sie können ein Add-on so konfigurieren, dass eine Vorschau mehrerer URL-Muster angezeigt wird, z. B. Links zu Supportanfragen, Leads und Mitarbeiterprofilen.

So sehen Nutzer eine Linkvorschau

Um eine Vorschau von Links aufzurufen, interagieren Nutzer mit Smartchips und Karten.

Nutzer sieht sich eine Karte in der Vorschau an

Wenn Nutzer eine URL in ein Dokument oder eine Tabelle eingeben oder einfügen, werden sie in Google Docs oder Google Tabellen aufgefordert, den Link durch einen Smartchip zu ersetzen. Der Smartchip enthält ein Symbol und einen kurzen Titel oder eine kurze Beschreibung des Inhalts des Links. Wenn der Nutzer den Mauszeiger auf den Chip bewegt, wird eine Kartenoberfläche mit einer Vorschau weiterer Informationen zur Datei oder zum Link angezeigt.

Im folgenden Video wird gezeigt, wie ein Nutzer einen Link in einen Smartchip umwandelt und eine Karte in der Vorschau ansieht:

So sehen Nutzer eine Vorschau von Links in Google Präsentationen

Smartchips von Drittanbietern werden für Linkvorschauen in Google Präsentationen nicht unterstützt. Wenn Nutzer eine URL in eine Präsentation eingeben oder einfügen, werden sie in Google Präsentationen aufgefordert, den Link durch seinen Titel als verknüpften Text anstelle eines Chips zu ersetzen. Wenn der Nutzer den Mauszeiger auf den Linktitel bewegt, wird eine Kartenoberfläche mit einer Vorschau der Informationen zum Link angezeigt.

Die folgende Abbildung zeigt, wie eine Linkvorschau in Google Präsentationen dargestellt wird:

Beispiel für eine Linkvorschau in Google Präsentationen

Vorbereitung

Apps Script

Node.js

Python

Java

Optional: Authentifizierung für einen Drittanbieterdienst einrichten

Wenn Ihr Add-on eine Verbindung zu einem Dienst herstellt, für den eine Autorisierung erforderlich ist, müssen sich Nutzer beim Dienst authentifizieren, um eine Vorschau von Links aufzurufen. Das bedeutet, dass Ihr Add-on den Autorisierungsvorgang aufrufen muss, wenn Nutzer zum ersten Mal einen Link aus Ihrem Dienst in eine Google Docs-, Google Sheets- oder Google Präsentationen-Datei einfügen.

Informationen zum Einrichten eines OAuth-Dienstes oder einer benutzerdefinierten Autorisierungsanfrage finden Sie unter Add-on mit einem Drittanbieterdienst verbinden.

In diesem Abschnitt wird beschrieben, wie Sie Linkvorschaubilder für Ihr Add-on einrichten. Dazu sind die folgenden Schritte erforderlich:

  1. Konfigurieren Sie Linkvorschauen im Manifest Ihres Add-ons.
  2. Erstellen Sie die Smartchip- und Kartenoberfläche für Ihre Links.

Linkvorschauen konfigurieren

Wenn Sie Linkvorschauen konfigurieren möchten, geben Sie die folgenden Abschnitte und Felder im Manifest Ihres Add-ons an:

  1. Fügen Sie unter addOns das Feld docs hinzu, um Google Docs zu erweitern, das Feld sheets, um Google Tabellen zu erweitern, und das Feld slides, um Google Präsentationen zu erweitern.
  2. Implementieren Sie in jedem Feld den linkPreviewTriggers-Trigger, der ein runFunction enthält. Diese Funktion definieren Sie im folgenden Abschnitt Smartchip und Karte erstellen.

    Informationen dazu, welche Felder Sie im linkPreviewTriggers-Trigger angeben können, finden Sie in der Referenzdokumentation zu Apps Script-Manifesten oder Bereitstellungsressourcen für andere Laufzeiten.

  3. Fügen Sie im Feld oauthScopes den Umfang https://www.googleapis.com/auth/workspace.linkpreview hinzu, damit Nutzer das Add-on autorisieren können, Links in ihrem Namen in der Vorschau anzuzeigen.

Im folgenden Manifest werden beispielsweise im Abschnitt oauthScopes und addons Linkvorschauen für einen Supportfalldienst konfiguriert.

{
  "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"
          }
        }
      ]
    }
  }
}

Im Beispiel zeigt das Google Workspace-Add-on Links für den Supportanfrage-Dienst eines Unternehmens an. Das Add-on gibt drei URL-Muster für die Vorschau von Links an. Wenn ein Link mit einem der URL-Muster übereinstimmt, erstellt und zeigt die Rückruffunktion caseLinkPreview eine Karte und einen Smartchip in Google Docs, Google Tabellen oder Google Präsentationen an und ersetzt die URL durch den Linktitel.

Smartchip und Karte erstellen

Wenn Sie einen Smartchip und eine Karte für einen Link zurückgeben möchten, müssen Sie alle Funktionen implementieren, die Sie im linkPreviewTriggers-Objekt angegeben haben.

Wenn ein Nutzer mit einem Link interagiert, der einem bestimmten URL-Muster entspricht, wird der Trigger linkPreviewTriggers ausgelöst und seine Rückruffunktion übergibt das Ereignisobjekt EDITOR_NAME.matchedUrl.url als Argument. Mit der Nutzlast dieses Ereignisobjekts erstellen Sie den Smartchip und die Karte für die Linkvorschau.

Wenn ein Nutzer beispielsweise die Vorschau des Links https://www.example.com/cases/123456 in Google Docs aufruft, wird die folgende Ereignisn-Nutzlast zurückgegeben:

JSON

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

Zum Erstellen der Kartenoberfläche verwenden Sie Widgets, um Informationen zum Link anzuzeigen. Sie können auch Aktionen erstellen, mit denen Nutzer den Link öffnen oder seinen Inhalt ändern können. Eine Liste der verfügbaren Widgets und Aktionen finden Sie unter Unterstützte Komponenten für Vorschaukarten.

So erstellst du den Smartchip und die Karte für eine Linkvorschau:

  1. Implementieren Sie die Funktion, die Sie im Abschnitt linkPreviewTriggers des Manifests Ihres Add-ons angegeben haben:
    1. Die Funktion muss ein Ereignisobjekt mit EDITOR_NAME.matchedUrl.url als Argument akzeptieren und ein einzelnes Card-Objekt zurückgeben.
    2. Wenn für Ihren Dienst eine Autorisierung erforderlich ist, muss die Funktion auch den Autorisierungsablauf aufrufen.
  2. Implementieren Sie für jede Vorschaukarte alle Callback-Funktionen, die für die Benutzeroberfläche eine Widget-Interaktivität bieten. Wenn Sie beispielsweise eine Schaltfläche mit der Aufschrift „Link ansehen“ einfügen, können Sie eine Aktion erstellen, die eine Rückruffunktion angibt, um den Link in einem neuen Fenster zu öffnen. Weitere Informationen zu Interaktionen mit Widgets finden Sie unter Add-on-Aktionen.

Im folgenden Code wird die Callback-Funktion caseLinkPreview für Google Docs erstellt:

Apps Script

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;
}

Unterstützte Komponenten für Vorschaukarten

Google Workspace-Add-ons unterstützen die folgenden Widgets und Aktionen für Karten mit Linkvorschau:

Apps Script

Feld „Kartendienst“ Typ
TextParagraph Widget
DecoratedText Widget
Image Widget
IconImage Widget
ButtonSet Widget
TextButton Widget
ImageButton Widget
Grid Widget
Divider Widget
OpenLink Aktion
Navigation Aktion
: Nur die Methode updateCard wird unterstützt.

JSON

Feld „Karte“ (google.apps.card.v1) Typ
TextParagraph Widget
DecoratedText Widget
Image Widget
Icon Widget
ButtonList Widget
Button Widget
Grid Widget
Divider Widget
OpenLink Aktion
Navigation Aktion
Nur die Methode updateCard wird unterstützt.

Vollständiges Beispiel: Add-on für Supportanfragen

Im folgenden Beispiel wird ein Google Workspace-Add-on verwendet, das eine Vorschau von Links zu den Supportfällen eines Unternehmens in Google Docs anzeigt.

Das Beispiel führt Folgendes aus:

  • Vorschau von Links zu Supportanfragen, z. B. https://www.example.com/support/cases/1234. Auf dem Smartchip wird ein Supportsymbol angezeigt und die Vorschaukarte enthält die Fall-ID und eine Beschreibung.
  • Wenn die Sprache des Nutzers auf Spanisch eingestellt ist, lokalisiert der Smartchip seine labelText auf Spanisch.

Manifest

Apps Script

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"
        }
      ]
    }
  }
}

Code

Apps Script

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;
  }

}