Linkvorschau mit Smartchips

Auf dieser Seite wird erläutert, wie Sie ein Google Workspace-Add-on erstellen, mit dem Nutzer von Google Docs, Google Tabellen und Google Präsentationen Links von einem Drittanbieterdienst als Vorschau ansehen können.

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

Vorschau von Links für Nutzer

Zur Vorschau von Links interagieren Nutzer mit Smartchips und Karten.

Der Nutzer sieht sich eine Karte in der Vorschau an.

Wenn Nutzer eine URL in ein Dokument eingeben oder einfügen, werden sie in Google Docs aufgefordert, den Link durch einen Smartchip zu ersetzen. Der Smartchip zeigt ein Symbol und einen kurzen Titel oder eine Beschreibung des Linkinhalts an. Wenn der Nutzer den Mauszeiger auf den Chip bewegt, wird eine Kartenoberfläche mit weiteren Informationen zur Datei oder zum Link angezeigt.

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

Vorschau von Links in Google Tabellen und Google Präsentationen anzeigen

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

In der folgenden Abbildung sehen Sie, wie eine Linkvorschau in Google Tabellen und Google Präsentationen gerendert wird:

Beispiel für die Linkvorschau in Google Tabellen und Google Präsentationen

Voraussetzungen

Apps Script

Node.js

Python

Java

Optional: Authentifizierung bei einem Drittanbieterdienst einrichten

Wenn Ihr Add-on eine Verbindung zu einem Dienst herstellt, der eine Autorisierung erfordert, müssen sich Nutzer beim Dienst authentifizieren, um Links in der Vorschau anzuzeigen. Wenn Nutzer also zum ersten Mal einen Link aus Ihrem Dienst in eine Datei in Google Docs, Google Tabellen oder Google Präsentationen einfügen, muss Ihr Add-on den Autorisierungsvorgang aufrufen.

Informationen zum Einrichten eines OAuth-Dienstes oder einer benutzerdefinierten Autorisierungsaufforderung findest du in den folgenden Anleitungen:

In diesem Abschnitt wird erläutert, wie Sie die Linkvorschau für Ihr Add-on einrichten. Dies umfasst die folgenden Schritte:

  1. Konfigurieren Sie die Linkvorschau in der Bereitstellungsressource oder Manifestdatei des Add-ons.
  2. Erstelle die Benutzeroberfläche für den Smartchip und die Karte für deine Links.

Linkvorschau konfigurieren

Geben Sie zum Konfigurieren der Linkvorschau die folgenden Abschnitte und Felder in der Bereitstellungsressource oder Manifestdatei des Add-ons an:

  1. Fügen Sie im Abschnitt addOns das Feld docs zum Erweitern von Docs, das Feld sheets zum Erweitern von Tabellen und das Feld slides zum Erweitern von Präsentationen hinzu.
  2. Implementieren Sie in jedem Feld den linkPreviewTriggers-Trigger, der eine 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-Manifestdateien oder unter Bereitstellungsressourcen für andere Laufzeiten.

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

Ein Beispiel finden Sie in den Abschnitten oauthScopes und addons der folgenden Bereitstellungsressource, in der Linkvorschauen für einen Supportfalldienst konfiguriert werden.

{
  "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 Supportfalldienst eines Unternehmens in der Vorschau an. Das Add-on gibt drei URL-Muster für Vorschaulinks an. Immer wenn ein Link mit einem der URL-Muster übereinstimmt, erstellt die Callback-Funktion caseLinkPreview eine Karte und einen Smartchip oder ersetzt die URL in Google Tabellen und Google Präsentationen durch den Linktitel.

Smartchip und Karte erstellen

Wenn du einen Smartchip und eine Karte für einen Link zurückgeben möchtest, musst du alle Funktionen implementieren, die du im linkPreviewTriggers-Objekt angegeben hast.

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

Wenn ein Nutzer beispielsweise in Google Docs den Link https://www.example.com/cases/123456 als Vorschau anzeigt, wird die folgende Ereignisnutzlast zurückgegeben:

JSON

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

Verwende Widgets, um Informationen zum Link anzuzeigen. Sie können auch Aktionen erstellen, mit denen Nutzer den Link öffnen oder den Inhalt ändern können. Eine Liste der verfügbaren Widgets und Aktionen findest du unter Unterstützte Komponenten für Vorschaukarten.

So erstellen Sie den Smartchip und die Karte für eine Linkvorschau:

  1. Implementieren Sie die Funktion, die Sie im Abschnitt linkPreviewTriggers der Bereitstellungsressource oder Manifestdatei des Add-ons angegeben haben:
    1. Die Funktion muss ein Ereignisobjekt akzeptieren, das EDITOR_NAME.matchedUrl.url als Argument enthält, und ein einzelnes Card-Objekt zurückgeben.
    2. Wenn Ihr Dienst eine Autorisierung erfordert, muss die Funktion auch den Autorisierungsablauf aufrufen.
  2. Implementieren Sie für jede Vorschaukarte alle Callback-Funktionen, die Widget-Interaktivität für die Schnittstelle bereitstellen. Wenn Sie beispielsweise die Schaltfläche „Link anzeigen“ einfügen, können Sie eine Aktion erstellen, die eine Callback-Funktion angibt, mit der der Link in einem neuen Fenster geöffnet wird. Weitere Informationen zu Widgetinteraktionen finden Sie unter Add-on-Aktionen.

Mit dem 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 Linkvorschaukarten:

Apps Script

Feld für den Kartendienst Typ
TextParagraph Widget
DecoratedText Widget
Image Widget
IconImage Widget
ButtonSet Widget
TextButton Widget
ImageButton Widget
Grid Widget
Divider Widget
OpenLink Aktion
Navigation Aktion
Es wird nur die Methode updateCard unterstützt.

JSON

Feld für 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
Es wird nur die Methode updateCard unterstützt.

Vollständiges Beispiel: Add-on für Supportfälle

Das folgende Beispiel enthält ein Google Workspace-Add-on, das Links zu den Supportfällen eines Unternehmens in Google Docs als Vorschau anzeigt.

Das Beispiel führt Folgendes aus:

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

Deployment-Ressource

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

}