Anteprima dei link con gli smart chip

Questa pagina spiega come creare un componente aggiuntivo di Google Workspace che consente agli utenti di Documenti, Fogli e Presentazioni Google di visualizzare l'anteprima dei link da un servizio di terze parti.

Un componente aggiuntivo di Google Workspace può rilevare i link del tuo servizio e chiedere agli utenti di visualizzarli in anteprima. Puoi configurare un componente aggiuntivo per visualizzare l'anteprima di più pattern URL, ad esempio link a richieste di assistenza, lead di vendita e profili dei dipendenti.

In che modo gli utenti hanno visualizzato l'anteprima dei link

Per visualizzare l'anteprima dei link, gli utenti interagiscono con smart chip e schede.

L'utente visualizza l'anteprima di una scheda

Quando gli utenti digitano o incollano un URL in un documento, Documenti Google chiede di sostituire il link con uno smart chip. Lo smart chip mostra un'icona e un breve titolo o una descrizione dei contenuti del link. Quando l'utente passa il mouse sopra il chip, viene visualizzata un'interfaccia della scheda che mostra in anteprima ulteriori informazioni sul file o sul link.

Il seguente video mostra in che modo un utente converte un link in uno smart chip e visualizza l'anteprima di una scheda:

In che modo gli utenti visualizzano l'anteprima dei link in Fogli e Presentazioni

Gli smart chip di terze parti non sono supportati per le anteprime dei link in Fogli e Presentazioni. Quando gli utenti digitano o incollano un URL in un foglio di lavoro o in una presentazione, Fogli o Presentazioni chiede di sostituire il link con il titolo come testo collegato anziché come chip. Quando l'utente passa il mouse sopra il titolo del link, viene visualizzata un'interfaccia a scheda che mostra un'anteprima delle informazioni sul link.

L'immagine seguente mostra come viene visualizzato l'anteprima di un link in Fogli e Presentazioni:

Esempio di anteprima link per Fogli e Presentazioni

Prerequisiti

Apps Script

  • Un account Google Workspace.
  • Un componente aggiuntivo di Google Workspace. Per creare un componente aggiuntivo, segui questa quickstart.

Node.js

  • Un account Google Workspace.
  • Un componente aggiuntivo di Google Workspace. Per creare un componente aggiuntivo, segui questa quickstart.

Python

  • Un account Google Workspace.
  • Un componente aggiuntivo di Google Workspace. Per creare un componente aggiuntivo, segui questa quickstart.

Java

  • Un account Google Workspace.
  • Un componente aggiuntivo di Google Workspace. Per creare un componente aggiuntivo, segui questa quickstart.

(Facoltativo) Configurare l'autenticazione su un servizio di terze parti

Se il componente aggiuntivo si connette a un servizio che richiede l'autorizzazione, gli utenti devono eseguire l'autenticazione al servizio per visualizzare l'anteprima dei link. Ciò significa che quando gli utenti incollano un link dal tuo servizio in un file di Documenti, Fogli o Presentazioni per la prima volta, il componente aggiuntivo deve richiamare il flusso di autorizzazione.

Per configurare un servizio OAuth o una richiesta di autorizzazione personalizzata, consulta una delle seguenti guide:

Questa sezione spiega come configurare le anteprime dei link per il componente aggiuntivo, che include i seguenti passaggi:

  1. Configura le anteprime dei link nella risorsa di deployment o nel file manifest del componente aggiuntivo.
  2. Crea l'interfaccia di smart chip e schede per i tuoi link.

Configura le anteprime dei link

Per configurare le anteprime dei link, specifica le sezioni e i campi seguenti nella risorsa di deployment o nel file manifest del componente aggiuntivo:

  1. Nella sezione addOns, aggiungi il campo docs per estendere Documenti, il campo sheets per estendere Fogli e il campo slides per estendere Presentazioni.
  2. In ogni campo, implementa l'attivatore linkPreviewTriggers che include un runFunction (puoi definire questa funzione nella sezione seguente, Creare lo smart chip e la scheda).

    Per scoprire quali campi puoi specificare nel trigger linkPreviewTriggers, consulta la documentazione di riferimento per i file manifest di Apps Script o le risorse di deployment per altri runtime.

  3. Nel campo oauthScopes, aggiungi l'ambito https://www.googleapis.com/auth/workspace.linkpreview in modo che gli utenti possano autorizzare il componente aggiuntivo a visualizzare l'anteprima dei link per loro conto.

Ad esempio, consulta la sezione oauthScopes e addons della seguente risorsa di deployment che configura le anteprime dei link per un servizio di richiesta di assistenza.

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

Nell'esempio, il componente aggiuntivo di Google Workspace mostra in anteprima i link per il servizio di richieste di assistenza di un'azienda. Il componente aggiuntivo specifica tre pattern URL per visualizzare l'anteprima dei link. Ogni volta che un link corrisponde a uno dei pattern URL, la funzione di callback caseLinkPreview crea e visualizza una scheda e uno smart chip oppure, in Fogli e Presentazioni, sostituisce l'URL con il titolo del link.

Creare lo smart chip e la scheda

Per restituire uno smart chip e una scheda per un link, devi implementare qualsiasi funzione specificata nell'oggetto linkPreviewTriggers.

Quando un utente interagisce con un link che corrisponde a un pattern URL specificato, l'attivatore linkPreviewTriggers si attiva e la sua funzione di callback trasmette l'oggetto evento EDITOR_NAME.matchedUrl.url come argomento. Puoi utilizzare il payload di questo oggetto evento per creare lo smart chip e la scheda per l'anteprima del link.

Ad esempio, se un utente visualizza l'anteprima del link https://www.example.com/cases/123456 in Documenti, viene restituito il seguente payload di evento:

JSON

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

Per creare l'interfaccia della scheda, puoi utilizzare i widget per visualizzare le informazioni sul link. Puoi anche creare azioni che consentano agli utenti di aprire il link o modificarne i contenuti. Per un elenco dei widget e delle azioni disponibili, vedi Componenti supportati per le schede di anteprima.

Per creare lo smart chip e la scheda per l'anteprima link:

  1. Implementa la funzione specificata nella sezione linkPreviewTriggers della risorsa di deployment o del file manifest del componente aggiuntivo:
    1. La funzione deve accettare un oggetto evento contenente EDITOR_NAME.matchedUrl.url come argomento e restituire un singolo oggetto Card.
    2. Se il servizio richiede l'autorizzazione, la funzione deve anche chiamare il flusso di autorizzazione.
  2. Per ogni scheda di anteprima, implementa tutte le funzioni di callback che forniscono interattività dei widget per l'interfaccia. Ad esempio, se includi un pulsante "Visualizza link", puoi creare un'azione che specifichi una funzione di callback per aprire il link in una nuova finestra. Per scoprire di più sulle interazioni con i widget, consulta Azioni aggiuntive.

Il seguente codice crea la funzione di callback caseLinkPreview per Documenti:

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

Componenti supportati per le schede di anteprima

I componenti aggiuntivi di Google Workspace supportano i seguenti widget e azioni per le schede di anteprima dei link:

Apps Script

Campo Card Service (Servizio carta) Tipo
TextParagraph Widget
DecoratedText Widget
Image Widget
IconImage Widget
ButtonSet Widget
TextButton Widget
ImageButton Widget
Grid Widget
Divider Widget
OpenLink Azione
Navigation Azione
È supportato soltanto il metodo updateCard.

JSON

Campo scheda (google.apps.card.v1) Tipo
TextParagraph Widget
DecoratedText Widget
Image Widget
Icon Widget
ButtonList Widget
Button Widget
Grid Widget
Divider Widget
OpenLink Azione
Navigation Azione
È supportato soltanto il metodo updateCard.

Esempio completo: componente aggiuntivo della richiesta di assistenza

L'esempio seguente include un componente aggiuntivo di Google Workspace che mostra in anteprima i link alle richieste di assistenza di un'azienda in Documenti Google.

Nell'esempio:

  • Visualizza in anteprima i link alle richieste di assistenza, come https://www.example.com/support/cases/1234. Lo smart chip mostra un'icona di assistenza, mentre la scheda di anteprima include l'ID richiesta e una descrizione.
  • Se la lingua dell'utente è impostata sullo spagnolo, lo smart chip localizza il suo labelText in spagnolo.

Risorsa di deployment

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

Codice

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

}