תצוגה מקדימה של קישורים עם צ'יפים חכמים

בדף זה מוסבר איך ליצור תוסף ל-Google Workspace שמאפשר למשתמשי Google Docs , Sheets ו-Slides להציג תצוגה מקדימה של קישורים משירות של צד שלישי.

תוסף של Google Workspace יכול לזהות את הקישורים לשירות שלכם ולבקש מהמשתמשים לראות אותם בתצוגה מקדימה. תוכלו להגדיר תוסף כדי להציג תצוגה מקדימה של מספר תבניות של כתובות URL, כמו קישורים לבקשות תמיכה, הפניות למכירות ופרופילים של עובדים.

כדי לראות תצוגה מקדימה של קישורים, המשתמשים משתמשים בצ'יפים חכמים ובכרטיסים.

המשתמש מציג כרטיס בתצוגה מקדימה

כשמשתמשים מקלידים או מדביקים כתובת URL במסמך, מוצגת ב-Google Docs בקשה להחליף את הקישור בצ'יפ חכם. בצ'יפ החכם מוצגים סמל וכותרת קצרה או תיאור של תוכן הקישור. כשהמשתמשים מעבירים את העכבר מעל לצ'יפ, הם רואים ממשק של כרטיס עם תצוגה מקדימה של מידע נוסף על הקובץ או הקישור.

בסרטון הבא מוצג איך משתמש ממיר קישור לצ'יפ חכם ומציג תצוגה מקדימה של כרטיס:

צ'יפים חכמים של צד שלישי לא נתמכים בתצוגה המקדימה של קישורים למפתחים ב-Sheets וב-Slides. כשמשתמשים מקלידים כתובת URL או מדביקים אותה בגיליון אלקטרוני או במצגת, ב-Sheets או במצגת מוצגת הנחיה להחליף את הקישור בכותרת של הקישור בתור טקסט מקושר במקום צ'יפ. כשהמשתמש מעביר את העכבר מעל כותרת הקישור, הוא רואה ממשק כרטיס עם תצוגה מקדימה של המידע על הקישור.

בתמונה הבאה אפשר לראות איך תצוגה מקדימה של קישור מעובדת ב-Sheets וב-Slides:

דוגמה לתצוגה מקדימה של קישור ב-Sheets וב-Slides

דרישות מוקדמות

Apps Script

Node.js

Python

Java

אופציונלי: הגדרת אימות לשירות צד שלישי

אם התוסף מתחבר לשירות שדורש הרשאה, המשתמשים יצטרכו לבצע אימות לשירות כדי לראות תצוגה מקדימה של הקישורים. כלומר, כשמשתמשים מדביקים בפעם הראשונה קישור מהשירות שלכם בקובץ Docs, Sheets או Slides, התוסף צריך להפעיל את תהליך ההרשאה.

תוכלו להיעזר באחד מהמדריכים הבאים כדי להגדיר שירות OAuth או בקשה להרשאה מותאמת אישית:

בקטע הזה נסביר איך להגדיר תצוגה מקדימה לקישורים של התוסף, כולל השלבים הבאים:

  1. הגדרת תצוגות מקדימות של קישורים במשאב הפריסה או בקובץ המניפסט של התוסף.
  2. איך יוצרים צ'יפ חכם וממשק של כרטיס לקישורים

הגדרת תצוגות מקדימות של קישורים

כדי להגדיר תצוגות מקדימות של קישורים, צריך לציין את הקטעים והשדות הבאים במשאב הפריסה או בקובץ המניפסט של התוסף:

  1. בקטע addOns, מוסיפים את השדה docs כדי להרחיב את Docs, את השדה sheets כדי להרחיב את Sheets, ואת השדה slides כדי להרחיב את Slides.
  2. בכל שדה, מטמיעים את הטריגר linkPreviewTriggers שכולל runFunction (את הפונקציה הזו מגדירים בקטע Build the Smart Chi and card).

    במסמכי העזרה של קובצי המניפסט של Apps Script או של משאבי הפריסה של זמני ריצה אחרים מוסבר אילו שדות אפשר לציין בהטריגר של linkPreviewTriggers.

  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, פונקציית הקריאה החוזרת caseLinkPreview יוצרת ומציגה כרטיס וצ'יפ חכם. לחלופין, ב-Sheets וב-Slides, מחליפה את כתובת ה-URL בכותרת הקישור.

יצירת הצ'יפ החכם והכרטיס

כדי להחזיר צ'יפ חכם וכרטיס לקישור, צריך להטמיע את כל הפונקציות שציינתם באובייקט linkPreviewTriggers.

כשמשתמש יוצר אינטראקציה עם קישור שתואם לדפוס כתובת URL מסוים, הטריגר linkPreviewTriggers מופעל ופונקציית הקריאה החוזרת שלו מעבירה את אובייקט האירוע EDITOR_NAME.matchedUrl.url כארגומנט. כדי ליצור את הצ'יפ החכם והכרטיס לתצוגה המקדימה של הקישור, צריך להשתמש במטען הייעודי (payload) של אובייקט האירוע הזה.

לדוגמה, בתוסף שמציין את תבנית כתובת ה-URL example.com/cases ב-Docs, כשמשתמש מציג בתצוגה מקדימה את הקישור https://www.example.com/cases/123456, מוחזר המטען הייעודי (payload) הבא של האירוע:

JSON

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

כדי ליצור את ממשק הכרטיס, משתמשים בווידג'טים להצגת מידע על הקישור. ניתן גם ליצור פעולות שמאפשרות למשתמשים לפתוח את הקישור או לשנות את התוכן שלו. במאמר רכיבים נתמכים לכרטיסי תצוגה מקדימה מופיעה רשימה של הווידג'טים והפעולות הזמינים.

כדי ליצור את הצ'יפ החכם והכרטיס לתצוגה מקדימה של הקישור:

  1. מטמיעים את הפונקציה שציינתם בקטע linkPreviewTriggers במשאב הפריסה או בקובץ המניפסט של התוסף:
    1. הפונקציה צריכה לקבל אובייקט אירוע שמכיל EDITOR_NAME.matchedUrl.url כארגומנט ולהחזיר אובייקט Card יחיד.
    2. אם השירות דורש הרשאה, הפונקציה צריכה גם להפעיל את תהליך ההרשאה.
  2. בכל כרטיס תצוגה מקדימה, מטמיעים פונקציות של התקשרות חזרה שמאפשרות אינטראקטיביות של ווידג'טים לממשק. לדוגמה, אם הוספתם לחצן עם הכיתוב View link (הצגת קישור), תוכלו ליצור פעולה שמציינת פונקציית קריאה חוזרת כדי לפתוח את הקישור בחלון חדש. למידע נוסף על אינטראקציות עם ווידג'טים, ראו פעולות בתוספים.

הקוד הבא יוצר את פונקציית הקריאה החוזרת caseLinkPreview עבור Docs:

Apps Script

apps-script/preview-links/preview-link.gs
/**
* Entry point for a support case link preview
*
* @param {!Object} event
* @return {!Card}
*/
// Creates a function that passes an event object as a parameter.
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 ID.
    const segments = event.docs.matchedUrl.url.split('/');
    const caseId = segments[segments.length - 1];

    // Builds a preview card with the case ID, title, and description
    const caseHeader = CardService.newCardHeader()
      .setTitle(`Case ${caseId}: Title bar is broken.`);
    const caseDescription = CardService.newTextParagraph()
      .setText('Customer can\'t view title on mobile device.');

    // 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();
  }
}

Node.js

node/preview-links/index.js
/**
 * 
 * A support case link preview.
 *
 * @param {!string} url
 * @return {!Card}
 */
function caseLinkPreview(url) {

  // Parses the URL to identify the case ID.
  const segments = url.split('/');
  const caseId = segments[segments.length - 1];

  // Returns the card.
  // Uses the text from the card's header for the title of the smart chip.
  return {
    header: {
      title: `Case ${caseId}: Title bar is broken.`
    },
    sections: [{
      widgets: [{
        textParagraph: {
          text: `Customer can't view title on mobile device.`
        }
      }]
    }]
  };
}

Python

python/preview-links/main.py

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

    # Parses the URL to identify the case ID.
    segments = url.split("/")
    case_id = segments[-1]

    # Returns the card.
    # Uses the text from the card's header for the title of the smart chip.
    return {
        "header": {"title": f"Case {case_id}: Title bar is broken."},
        "sections": [
            {
                "widgets": [
                    {
                        "textParagraph": {
                            "text": "Customer can't view title on mobile device."
                        }
                    }
                ]
            }
        ],
    }

Java

java/preview-links/src/main/java/PreviewLink.java
/**
 * Creates a case link preview card.
 *
 * @param url A URL.
 * @return A case link preview card.
 */
Card caseLinkPreview(String url) {
  String[] segments = url.split("/");
  String caseId = segments[segments.length - 1];

  CardHeader cardHeader = new CardHeader();
  cardHeader.setTitle(String.format("Case %s: Title bar is broken.", caseId));

  TextParagraph textParagraph = new TextParagraph();
  textParagraph.setText("Customer can't view title on mobile device.");

  WidgetMarkup widget = new WidgetMarkup();
  widget.setTextParagraph(textParagraph);
  Section section = new Section();
  section.setWidgets(List.of(widget));

  Card card = new Card();
  card.setHeader(cardHeader);
  card.setSections(List.of(section));

  return card;
}

הרכיבים הנתמכים בכרטיסים של תצוגה מקדימה

תוספים ל-Google Workspace תומכים בווידג'טים ובפעולות הבאים בכרטיסי תצוגה מקדימה של קישורים:

Apps Script

שדה שירות הכרטיסים תיאור
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. בצ'יפ החכם מוצג סמל תמיכה, וכרטיס התצוגה המקדימה כולל את מספר הפנייה ותיאור.
  • תצוגה מקדימה של קישורים לנציגי בקשות תמיכה, כמו https://www.example.com/people/rosario-cruz. בצ'יפ החכם מוצג סמל של אדם, וכרטיס התצוגה המקדימה כולל את שם העובד, כתובת האימייל שלו, תיאור התפקיד ותמונת הפרופיל שלו.
  • אם הלוקאל של המשתמש מוגדר לספרדית, הצ'יפ החכם מבצע לוקליזציה של labelText לספרדית.

משאב פריסה

Apps Script

apps-script/preview-links/appsscript.json
{
  "timeZone": "America/New_York",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/workspace.linkpreview"
  ],
  "addOns": {
    "common": {
      "name": "Preview support cases",
      "logoUrl": "https://developers.google.com/workspace/add-ons/images/link-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"
        },
        {
          "runFunction": "peopleLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "people"
            }
          ],
          "labelText": "People",
          "localizedLabelText": {
            "es": "Personas"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/person-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/link-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"
        },
        {
          "runFunction": "URL",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "people"
            }
          ],
          "labelText": "People",
          "localizedLabelText": {
            "es": "Personas"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/person-icon.png"
        }
      ]
    }
  }
}

קוד

Apps Script

apps-script/preview-links/preview-link.gs
/**
* Entry point for a support case link preview
*
* @param {!Object} event
* @return {!Card}
*/
// Creates a function that passes an event object as a parameter.
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 ID.
    const segments = event.docs.matchedUrl.url.split('/');
    const caseId = segments[segments.length - 1];

    // Builds a preview card with the case ID, title, and description
    const caseHeader = CardService.newCardHeader()
      .setTitle(`Case ${caseId}: Title bar is broken.`);
    const caseDescription = CardService.newTextParagraph()
      .setText('Customer can\'t view title on mobile device.');

    // 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();
  }
}


/**
* Entry point for an employee profile link preview
*
* @param {!Object} event
* @return {!Card}
*/
function peopleLinkPreview(event) {

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

    // Builds a preview card with an employee's name, title, email, and profile photo.
    const userHeader = CardService.newCardHeader().setTitle("Rosario Cruz");
    const userImage = CardService.newImage()
      .setImageUrl("https://developers.google.com/workspace/add-ons/images/employee-profile.png");
    const userInfo = CardService.newDecoratedText()
      .setText("rosario@example.com")
      .setBottomLabel("Case Manager")
      .setIcon(CardService.Icon.EMAIL);
    const userSection = CardService.newCardSection()
      .addWidget(userImage)
      .addWidget(userInfo);

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

Node.js

node/preview-links/index.js
const UrlParser = require('url');

/**
 * Responds to any HTTP request.
 *
 * @param {Object} req HTTP request context.
 * @param {Object} res HTTP response context.
 */
exports.createLinkPreview = (req, res) => {
  const event = req.body;
  if (event.docs.matchedUrl.url) {
    res.json(createCard(event.docs.matchedUrl.url));
  }
};

/**
 * Creates a preview link card for either a case link or people link.
 * 
 * @param {!String} url
 * @return {!Card}
 */
function createCard(url) {
  const parsedUrl = UrlParser.parse(url);
  if (parsedUrl.hostname === 'www.example.com') {
    if (parsedUrl.path.startsWith('/support/cases/')) {
      return caseLinkPreview(url);
    }

    if (parsedUrl.path.startsWith('/people/')) {
      return peopleLinkPreview();
    }
  }
}


/**
 * 
 * A support case link preview.
 *
 * @param {!string} url
 * @return {!Card}
 */
function caseLinkPreview(url) {

  // Parses the URL to identify the case ID.
  const segments = url.split('/');
  const caseId = segments[segments.length - 1];

  // Returns the card.
  // Uses the text from the card's header for the title of the smart chip.
  return {
    header: {
      title: `Case ${caseId}: Title bar is broken.`
    },
    sections: [{
      widgets: [{
        textParagraph: {
          text: `Customer can't view title on mobile device.`
        }
      }]
    }]
  };
}


/**
 * An employee profile link preview.
 *
 * @return {!Card}
 */
function peopleLinkPreview() {

  // Builds a preview card with an employee's name, title, email, and profile photo.
  // Returns the card. Uses the text from the card's header for the title of the smart chip.
  return {
    header: {
      title: "Rosario Cruz"
    },
    sections: [{
      widgets: [
        {
          image: {
            imageUrl: 'https://developers.google.com/workspace/add-ons/images/employee-profile.png'
          }
        }, {
          keyValue: {
            icon: "EMAIL",
            content: "rosario@example.com",
            bottomLabel: "Case Manager"
          }
        }
      ]
    }]
  };
}

Python

python/preview-links/main.py
from typing import Any, Mapping
from urllib.parse import urlparse

import flask
import functions_framework


@functions_framework.http
def create_link_preview(req: flask.Request):
    """Responds to any HTTP request.
    Args:
      req: HTTP request context.
    Returns:
      The response object.
    """
    event = req.get_json(silent=True)
    if event["docs"]["matchedUrl"]["url"]:
        return create_card(event["docs"]["matchedUrl"]["url"])


def create_card(url):
    """Creates a preview link card for either a case link or people link.
    Args:
      url: The matched url.
    Returns:
      A case link preview card or a people link preview card.
    """
    parsed_url = urlparse(url)
    if parsed_url.hostname != "www.example.com":
        return {}

    if parsed_url.path.startswith("/support/cases/"):
        return case_link_preview(url)

    if parsed_url.path.startswith("/people/"):
        return people_link_preview()

    return {}




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

    # Parses the URL to identify the case ID.
    segments = url.split("/")
    case_id = segments[-1]

    # Returns the card.
    # Uses the text from the card's header for the title of the smart chip.
    return {
        "header": {"title": f"Case {case_id}: Title bar is broken."},
        "sections": [
            {
                "widgets": [
                    {
                        "textParagraph": {
                            "text": "Customer can't view title on mobile device."
                        }
                    }
                ]
            }
        ],
    }




def people_link_preview():
    """An employee profile link preview.
    Returns:
      A people link preview card.
    """

    # Builds a preview card with an employee's name, title, email, and profile photo.
    # Returns the card. Uses the text from the card's header for the title of the smart chip.
    return {
        "header": {"title": "Rosario Cruz"},
        "sections": [
            {
                "widgets": [
                    {
                        "image": {
                            "imageUrl": "https:#developers.google.com/workspace/add-ons/images/employee-profile.png"
                        }
                    },
                    {
                        "keyValue": {
                            "icon": "EMAIL",
                            "content": "rosario@example.com",
                            "bottomLabel": "Case Manager",
                        }
                    },
                ]
            }
        ],
    }

Java

java/preview-links/src/main/java/PreviewLink.java
import com.google.api.services.chat.v1.model.Card;
import com.google.api.services.chat.v1.model.CardHeader;
import com.google.api.services.chat.v1.model.Image;
import com.google.api.services.chat.v1.model.KeyValue;
import com.google.api.services.chat.v1.model.Section;
import com.google.api.services.chat.v1.model.TextParagraph;
import com.google.api.services.chat.v1.model.WidgetMarkup;
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.JsonObject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

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

  /**
   * Responds to any HTTP request.
   *
   * @param request  An HTTP request context.
   * @param response An HTTP response context.
   */
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonObject body = gson.fromJson(request.getReader(), JsonObject.class);
    String url = body.getAsJsonObject("docs")
        .getAsJsonObject("matchedUrl")
        .get("url")
        .getAsString();

    response.getWriter().write(gson.toJson(createCard(url)));
  }

  /**
   * Creates a preview link card for either a case link or people link.
   *
   * @param url A URL.
   * @return A case link preview card or a people link preview card.
   */
  Card createCard(String url) throws MalformedURLException {
    URL parsedURL = new URL(url);

    if (!parsedURL.getHost().equals("www.example.com")) {
      return new Card();
    }

    if (parsedURL.getPath().startsWith("/support/cases/")) {
      return caseLinkPreview(url);
    }

    if (parsedURL.getPath().startsWith("/people/")) {
      return peopleLinkPreview();
    }

    return new Card();
  }


  /**
   * Creates a case link preview card.
   *
   * @param url A URL.
   * @return A case link preview card.
   */
  Card caseLinkPreview(String url) {
    String[] segments = url.split("/");
    String caseId = segments[segments.length - 1];

    CardHeader cardHeader = new CardHeader();
    cardHeader.setTitle(String.format("Case %s: Title bar is broken.", caseId));

    TextParagraph textParagraph = new TextParagraph();
    textParagraph.setText("Customer can't view title on mobile device.");

    WidgetMarkup widget = new WidgetMarkup();
    widget.setTextParagraph(textParagraph);
    Section section = new Section();
    section.setWidgets(List.of(widget));

    Card card = new Card();
    card.setHeader(cardHeader);
    card.setSections(List.of(section));

    return card;
  }


  /**
   * Creates a people link preview card.
   *
   * @return A people link preview card.
   */
  Card peopleLinkPreview() {
    CardHeader cardHeader = new CardHeader();
    cardHeader.setTitle("Rosario Cruz");

    Image image = new Image();
    image.setImageUrl("https://developers.google.com/workspace/add-ons/images/employee-profile.png");

    WidgetMarkup imageWidget = new WidgetMarkup();
    imageWidget.setImage(image);

    KeyValue keyValue = new KeyValue();
    keyValue.setIcon("EMAIL");
    keyValue.setContent("rosario@example.com");
    keyValue.setBottomLabel("Case Manager");

    WidgetMarkup keyValueWidget = new WidgetMarkup();
    keyValueWidget.setKeyValue(keyValue);

    Section section = new Section();
    section.setWidgets(List.of(imageWidget, keyValueWidget));

    Card card = new Card();
    card.setHeader(cardHeader);
    card.setSections(List.of(section));

    return card;
  }

}