Xem trước đường liên kết bằng khối thông minh

Trang này giải thích cách tạo tiện ích bổ sung Google Workspace cho phép người dùng Google Tài liệu, Trang tính và Trang trình bày xem trước các đường liên kết từ một dịch vụ bên thứ ba.

Tiện ích bổ sung của Google Workspace có thể phát hiện đường liên kết của dịch vụ và nhắc người dùng xem trước các đường liên kết đó. Bạn có thể định cấu hình một tiện ích bổ sung để xem trước nhiều mẫu URL, chẳng hạn như đường liên kết đến các trường hợp hỗ trợ, khách hàng tiềm năng và hồ sơ nhân viên.

Cách người dùng xem trước đường liên kết

Để xem trước đường liên kết, người dùng tương tác với khối thông minhthẻ.

Người dùng xem trước thẻ

Khi người dùng nhập hoặc dán URL vào tài liệu hoặc bảng tính, Google Tài liệu hoặc Google Trang tính sẽ nhắc họ thay thế đường liên kết bằng một khối thông minh. Khối thông minh hiển thị một biểu tượng và tiêu đề ngắn hoặc nội dung mô tả về nội dung của đường liên kết. Khi di chuột qua khối, người dùng sẽ thấy một giao diện thẻ cho thấy trước thêm thông tin về tệp hoặc đường liên kết.

Video sau đây cho thấy cách người dùng chuyển đổi đường liên kết thành khối thông minh và xem trước thẻ:

Cách người dùng xem trước đường liên kết trong Trang trình bày

Khối thông minh của bên thứ ba không được hỗ trợ cho bản xem trước đường liên kết trong Trang trình bày. Khi người dùng nhập hoặc dán một URL vào bản trình bày, Trang trình bày sẽ nhắc họ thay thế liên kết bằng tiêu đề của liên kết dưới dạng văn bản được liên kết thay vì khối. Khi di chuột qua tiêu đề đường liên kết, người dùng sẽ thấy một giao diện thẻ xem trước thông tin về đường liên kết đó.

Hình ảnh sau đây cho thấy cách bản xem trước đường liên kết hiển thị trong Trang trình bày:

Ví dụ về bản xem trước đường liên kết cho Trang trình bày

Điều kiện tiên quyết

Apps Script

  • Tài khoản Google Workspace.
  • Một tiện ích bổ sung của Google Workspace. Để tạo một tiện ích bổ sung, hãy làm theo hướng dẫn bắt đầu nhanh này.

Node.js

  • Tài khoản Google Workspace.
  • Một tiện ích bổ sung của Google Workspace. Để tạo một tiện ích bổ sung, hãy làm theo hướng dẫn bắt đầu nhanh này.

Python

  • Tài khoản Google Workspace.
  • Một tiện ích bổ sung của Google Workspace. Để tạo một tiện ích bổ sung, hãy làm theo hướng dẫn bắt đầu nhanh này.

Java

  • Tài khoản Google Workspace.
  • Một tiện ích bổ sung của Google Workspace. Để tạo một tiện ích bổ sung, hãy làm theo hướng dẫn bắt đầu nhanh này.

Không bắt buộc: Thiết lập tính năng xác thực cho một dịch vụ của bên thứ ba

Nếu tiện ích bổ sung của bạn kết nối với một dịch vụ yêu cầu uỷ quyền, thì người dùng phải xác thực với dịch vụ đó để xem trước đường liên kết. Điều này có nghĩa là khi người dùng dán đường liên kết từ dịch vụ của bạn vào tệp Tài liệu, Trang tính hoặc Trang trình bày lần đầu tiên, tiện ích bổ sung của bạn phải gọi quy trình uỷ quyền.

Để thiết lập dịch vụ OAuth hoặc lời nhắc uỷ quyền tuỳ chỉnh, hãy xem phần Kết nối tiện ích bổ sung với dịch vụ của bên thứ ba.

Phần này giải thích cách thiết lập bản xem trước đường liên kết cho tiện ích bổ sung, bao gồm các bước sau:

  1. Định cấu hình bản xem trước đường liên kết trong tệp kê khai của tiện ích bổ sung.
  2. Tạo giao diện thẻ và khối thông minh cho các đường liên kết.

Định cấu hình bản xem trước đường liên kết

Để định cấu hình bản xem trước đường liên kết, hãy chỉ định các phần và trường sau trong tệp kê khai của tiện ích bổ sung:

  1. Trong mục addOns, hãy thêm trường docs để mở rộng Tài liệu, trường sheets để mở rộng Trang tính và trường slides để mở rộng Trang trình bày.
  2. Trong mỗi trường, hãy triển khai trình kích hoạt linkPreviewTriggers bao gồm runFunction (Bạn xác định hàm này trong phần sau, Tạo khối và thẻ thông minh).

    Để tìm hiểu về những trường mà bạn có thể chỉ định trong trình kích hoạt linkPreviewTriggers, hãy xem tài liệu tham khảo về tệp kê khai Apps Script hoặc tài nguyên triển khai cho các môi trường thời gian chạy khác.

  3. Trong trường oauthScopes, hãy thêm phạm vi https://www.googleapis.com/auth/workspace.linkpreview để người dùng có thể uỷ quyền cho tiện ích bổ sung xem trước đường liên kết thay mặt họ.

Ví dụ: hãy xem phần oauthScopesaddons của tệp kê khai sau đây để định cấu hình bản xem trước đường liên kết cho dịch vụ yêu cầu hỗ trợ.

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

Trong ví dụ này, tiện ích bổ sung Google Workspace xem trước các đường liên kết đến dịch vụ trường hợp hỗ trợ của một công ty. Tiện ích bổ sung này chỉ định ba mẫu URL để xem trước đường liên kết. Bất cứ khi nào một đường liên kết khớp với một trong các mẫu URL, hàm gọi lại caseLinkPreview sẽ tạo và hiển thị một thẻ và một khối thông minh trong Tài liệu, Trang tính hoặc Trang trình bày, đồng thời thay thế URL bằng tiêu đề đường liên kết.

Tạo khối và thẻ thông minh

Để trả về một khối thông minh và thẻ cho một đường liên kết, bạn phải triển khai mọi hàm mà bạn đã chỉ định trong đối tượng linkPreviewTriggers.

Khi người dùng tương tác với một đường liên kết khớp với mẫu URL đã chỉ định, trình kích hoạt linkPreviewTriggers sẽ kích hoạt và hàm gọi lại của trình kích hoạt này sẽ truyền đối tượng sự kiện EDITOR_NAME.matchedUrl.url dưới dạng đối số. Bạn sử dụng tải trọng của đối tượng sự kiện này để tạo khối và thẻ thông minh cho bản xem trước đường liên kết.

Ví dụ: nếu người dùng xem trước đường liên kết https://www.example.com/cases/123456 trong Tài liệu, thì hệ thống sẽ trả về tải trọng sự kiện sau:

JSON

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

Để tạo giao diện thẻ, bạn sử dụng các tiện ích để hiển thị thông tin về đường liên kết. Bạn cũng có thể tạo các hành động cho phép người dùng mở đường liên kết hoặc sửa đổi nội dung của đường liên kết đó. Để biết danh sách các tiện ích và hành động có sẵn, hãy xem phần Thành phần được hỗ trợ cho thẻ xem trước.

Cách tạo khối thông minh và thẻ cho bản xem trước đường liên kết:

  1. Triển khai hàm mà bạn đã chỉ định trong phần linkPreviewTriggers của tệp kê khai của tiện ích bổ sung:
    1. Hàm này phải chấp nhận một đối tượng sự kiện chứa EDITOR_NAME.matchedUrl.url làm đối số và trả về một đối tượng Card duy nhất.
    2. Nếu dịch vụ của bạn yêu cầu uỷ quyền, thì hàm cũng phải gọi quy trình uỷ quyền.
  2. Đối với mỗi thẻ xem trước, hãy triển khai mọi hàm gọi lại cung cấp tính năng tương tác với tiện ích cho giao diện. Ví dụ: nếu thêm một nút có nội dung "Xem đường liên kết", bạn có thể tạo một thao tác chỉ định một hàm gọi lại để mở đường liên kết trong một cửa sổ mới. Để tìm hiểu thêm về các lượt tương tác với tiện ích, hãy xem phần Thao tác bổ sung.

Mã sau đây tạo hàm callback caseLinkPreview cho Docs:

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

Các thành phần được hỗ trợ cho thẻ xem trước

Các tiện ích bổ sung của Google Workspace hỗ trợ các tiện ích và thao tác sau đây cho thẻ xem trước đường liên kết:

Apps Script

Trường Dịch vụ thẻ Loại
TextParagraph Tiện ích
DecoratedText Tiện ích
Image Tiện ích
IconImage Tiện ích
ButtonSet Tiện ích
TextButton Tiện ích
ImageButton Tiện ích
Grid Tiện ích
Divider Tiện ích
OpenLink Hành động
Navigation Thao tác
Chỉ hỗ trợ phương thức updateCard.

JSON

Trường Thẻ (google.apps.card.v1) Loại
TextParagraph Tiện ích
DecoratedText Tiện ích
Image Tiện ích
Icon Tiện ích
ButtonList Tiện ích
Button Tiện ích
Grid Tiện ích
Divider Tiện ích
OpenLink Hành động
Navigation Thao tác
Chỉ hỗ trợ phương thức updateCard.

Ví dụ hoàn chỉnh: Tiện ích bổ sung về yêu cầu hỗ trợ

Ví dụ sau đây giới thiệu một tiện ích bổ sung của Google Workspace giúp xem trước các đường liên kết đến các trường hợp hỗ trợ của công ty trong Google Tài liệu.

Ví dụ này thực hiện những việc sau:

  • Xem trước đường liên kết đến các trường hợp hỗ trợ, chẳng hạn như https://www.example.com/support/cases/1234. Khối thông minh hiển thị một biểu tượng hỗ trợ và thẻ xem trước bao gồm mã yêu cầu và nội dung mô tả.
  • Nếu ngôn ngữ của người dùng được đặt thành tiếng Tây Ban Nha, thì khối thông minh sẽ bản địa hoá labelText thành tiếng Tây Ban Nha.

Tệp kê khai

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

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

}