پیش نمایش لینک ها با تراشه های هوشمند

این صفحه نحوه ساخت افزونه Google Workspace را توضیح می‌دهد که به کاربران Google Docs، Sheets و Slides امکان پیش‌نمایش پیوندها از یک سرویس شخص ثالث را می‌دهد.

یک افزونه Google Workspace می‌تواند پیوندهای سرویس شما را شناسایی کند و از کاربران بخواهد آنها را پیش‌نمایش کنند. می‌توانید افزونه‌ای را برای پیش‌نمایش الگوهای URL متعدد، مانند پیوندهایی به موارد پشتیبانی، سرنخ‌های فروش، و نمایه‌های کارمندان، پیکربندی کنید.

نحوه پیش نمایش لینک ها توسط کاربران

برای پیش نمایش پیوندها، کاربران با تراشه ها و کارت های هوشمند تعامل دارند.

کاربر یک کارت را پیش‌نمایش می‌کند

هنگامی که کاربران URL را در یک سند تایپ یا جای‌گذاری می‌کنند، Google Docs از آنها می‌خواهد پیوند را با یک تراشه هوشمند جایگزین کنند. تراشه هوشمند یک نماد و عنوان کوتاه یا شرح محتوای پیوند را نمایش می دهد. وقتی کاربر روی تراشه می‌چرخد، رابط کارتی را می‌بیند که اطلاعات بیشتری درباره فایل یا پیوند پیش‌نمایش می‌کند.

ویدئوی زیر نشان می دهد که چگونه یک کاربر یک لینک را به یک تراشه هوشمند تبدیل می کند و یک کارت را پیش نمایش می کند:

چگونه کاربران پیوندها را در برگه‌ها و اسلایدها پیش‌نمایش می‌کنند

تراشه‌های هوشمند شخص ثالث برای پیش‌نمایش پیوند در کاربرگ‌نگار و اسلایدنگار پشتیبانی نمی‌شوند. هنگامی که کاربران URL را در صفحه گسترده یا ارائه می‌نویسند یا جای‌گذاری می‌کنند، Sheets یا Slides از آنها می‌خواهد که پیوند را با عنوان آن به‌عنوان متن پیوندی به جای تراشه جایگزین کنند. وقتی کاربر روی عنوان پیوند می‌چرخد، یک رابط کارتی را می‌بیند که اطلاعات مربوط به پیوند را پیش‌نمایش می‌کند.

تصویر زیر نحوه نمایش پیش‌نمایش پیوند در برگه‌ها و اسلایدها را نشان می‌دهد:

نمونه پیش‌نمایش پیوند برای برگه‌ها و اسلایدها

پیش نیازها

اسکریپت برنامه ها

Node.js

پایتون

جاوا

اختیاری: احراز هویت را برای یک سرویس شخص ثالث تنظیم کنید

اگر برافزای شما به سرویسی متصل می‌شود که نیاز به مجوز دارد، کاربران باید برای پیش‌نمایش پیوندها به سرویس احراز هویت کنند. این بدان معناست که وقتی کاربران برای اولین بار پیوندی را از سرویس شما در فایل سندنگار، کاربرگ‌نگار یا اسلاید قرار می‌دهند، افزونه شما باید جریان مجوز را فراخوانی کند.

برای تنظیم یک سرویس OAuth یا درخواست مجوز سفارشی، به یکی از راهنماهای زیر مراجعه کنید:

این بخش نحوه تنظیم پیش نمایش پیوندها را برای افزونه خود توضیح می دهد که شامل مراحل زیر است:

  1. پیش نمایش پیوندها را در منبع استقرار افزونه یا فایل مانیفست خود پیکربندی کنید .
  2. تراشه هوشمند و رابط کارت را برای پیوندهای خود بسازید .

پیش نمایش پیوندها را پیکربندی کنید

برای پیکربندی پیش‌نمایش پیوند، بخش‌ها و فیلدهای زیر را در منبع استقرار افزونه یا فایل مانیفست خود مشخص کنید:

  1. در بخش addOns ، فیلد docs را برای گسترش Docs، فیلد sheets را برای گسترش Sheets و فیلد slides را برای گسترش Slides اضافه کنید.
  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 یک کارت و یک تراشه هوشمند می سازد و نمایش می دهد، یا در Sheets و Slides، URL را با عنوان پیوند جایگزین می کند.

تراشه و کارت هوشمند را بسازید

برای برگرداندن یک تراشه و کارت هوشمند برای یک پیوند، باید هر عملکردی را که در شی linkPreviewTriggers مشخص کرده اید، پیاده سازی کنید.

وقتی کاربر با پیوندی که با یک الگوی URL مشخص مطابقت دارد تعامل می‌کند، linkPreviewTriggers فعال می‌شود و تابع تماس آن، شی رویداد EDITOR_NAME .matchedUrl.url را به عنوان آرگومان ارسال می‌کند. شما از بار این شی رویداد برای ساخت تراشه و کارت هوشمند برای پیش نمایش پیوند خود استفاده می کنید.

برای مثال، اگر کاربری پیوند https://www.example.com/cases/123456 را در Docs پیش‌نمایش کند، بار رویداد زیر برگردانده می‌شود:

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/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/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 Docs پیش‌نمایش می‌کند.

مثال موارد زیر را انجام می دهد:

  • پیوندهای موارد پشتیبانی مانند 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/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/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;
  }

}