Ссылки для предварительного просмотра

Чтобы предотвратить переключение контекста, когда пользователи делятся ссылкой в ​​Google Chat, ваше приложение Chat может предварительно просмотреть ссылку, прикрепив к их сообщению карточку , которая дает дополнительную информацию и позволяет людям совершать действия прямо из Google Chat.

Например, представьте себе пространство Google Chat, включающее всех агентов по обслуживанию клиентов компании, а также приложение Chat под названием Case-y. Агенты часто делятся ссылками на обращения в службу поддержки клиентов в чате, и каждый раз, когда они это делают, их коллегам приходится открывать ссылку на обращение, чтобы просмотреть такие подробности, как правопреемник, статус и тема. Аналогично, если кто-то хочет взять на себя ответственность за обращение или изменить его статус, ему необходимо открыть ссылку.

Предварительный просмотр ссылки позволяет резидентному приложению чата пространства Case-y прикреплять карточку с указанием правопреемника, статуса и темы всякий раз, когда кто-то делится ссылкой на обращение. Кнопки на карточке позволяют агентам взять на себя ответственность за обращение и изменить статус прямо из потока чата.

Когда кто-то добавляет ссылку в свое сообщение, появляется метка, сообщающая ему, что приложение чата может просмотреть ссылку.

Чип, указывающий, что приложение чата может предварительно просмотреть ссылку

После отправки сообщения ссылка отправляется в приложение «Чат», которое затем генерирует и прикрепляет карточку к сообщению пользователя.

Приложение чата просматривает ссылку, прикрепив карточку к сообщению

Помимо ссылки, карточка предоставляет дополнительную информацию о ссылке, включая интерактивные элементы, такие как кнопки. Ваше приложение Chat может обновлять прикрепленную карточку в ответ на действия пользователя, например нажатия кнопок.

Если кто-то не хочет, чтобы приложение Chat просматривало его ссылку, прикрепив карточку к сообщению, он может запретить предварительный просмотр, нажав кнопку на чипе предварительного просмотра. Пользователи могут удалить прикрепленную карту в любое время, нажав «Удалить предварительный просмотр» .

Предварительные условия

Node.js

Приложение Google Chat с интерактивными функциями. Чтобы создать интерактивное приложение чата с использованием службы HTTP, выполните это краткое руководство .

Питон

Приложение Google Chat с интерактивными функциями. Чтобы создать интерактивное приложение чата с использованием службы HTTP, выполните это краткое руководство .

Ява

Приложение Google Chat с интерактивными функциями. Чтобы создать интерактивное приложение чата с использованием службы HTTP, выполните это краткое руководство .

Скрипт приложений

Приложение Google Chat с интерактивными функциями. Чтобы создать интерактивное приложение чата с помощью Apps Script, выполните это краткое руководство .

Зарегистрируйте определенные ссылки, такие как example.com , support.example.com и support.example.com/cases/ , в качестве шаблонов URL-адресов на странице конфигурации вашего приложения Chat в консоли Google Cloud, чтобы ваше приложение Chat могло их просмотреть.

Меню конфигурации предварительного просмотра ссылок

  1. Откройте консоль Google Cloud .
  2. Рядом с надписью «Google Cloud» нажмите стрелку и откройте проект приложения Chat.
  3. В поле поиска введите Google Chat API и нажмите Google Chat API .
  4. Нажмите «Управление» > «Конфигурация» .
  5. В разделе «Предварительный просмотр ссылок» добавьте или измените шаблон URL-адреса.
    1. Чтобы настроить предварительный просмотр ссылок для нового шаблона URL-адреса, нажмите «Добавить шаблон URL-адреса» .
    2. Чтобы изменить конфигурацию существующего шаблона URL-адреса, нажмите стрелку вниз .
  6. В поле Шаблон хоста введите домен шаблона URL-адреса. Приложение Chat будет просматривать ссылки на этот домен.

    Чтобы иметь ссылки предварительного просмотра приложения Chat для определенного субдомена, например subdomain.example.com , включите субдомен.

    Чтобы иметь ссылки на предварительный просмотр приложения Chat для всего домена, укажите в качестве поддомена подстановочный знак со звездочкой (*). Например, *.example.com соответствует subdomain.example.com и any.number.of.subdomains.example.com .

  7. В поле Префикс пути введите путь для добавления к домену шаблона хоста.

    Чтобы сопоставить все URL-адреса в домене шаблона узла, оставьте префикс пути пустым.

    Например, если шаблон хоста — support.example.com , чтобы сопоставить URL-адреса обращений, размещенных по адресу support.example.com/cases/ , введите cases/ .

  8. Нажмите Готово .

  9. Нажмите Сохранить .

Теперь, когда кто-то добавляет ссылку, соответствующую шаблону URL-адреса предварительного просмотра ссылки, на сообщение в пространстве чата, которое включает ваше приложение Chat, ваше приложение просматривает ссылку.

После того как вы настроите предварительный просмотр для конкретной ссылки, ваше приложение Chat сможет распознать и просмотреть ссылку, прикрепив к ней дополнительную информацию.

Если в пространствах чата, включающих ваше приложение Chat, чье-либо сообщение содержит ссылку, соответствующую шаблону URL-адреса предварительного просмотра ссылки, ваше приложение Chat получает событие взаимодействия MESSAGE . Полезная нагрузка JSON для события взаимодействия содержит поле matchedUrl :

JSON

message: {
  matchedUrl: {
    url: "https://support.example.com/cases/case123"
  },
  ... // other message attributes redacted
}

Проверив наличие поля matchedUrl в полезных данных события MESSAGE , ваше приложение чата может добавить информацию в сообщение с предварительно просмотренной ссылкой. Ваше приложение чата может либо ответить обычным текстовым сообщением, либо прикрепить карточку.

Ответить текстовым сообщением

Для базовых ответов ваше приложение чата может предварительно просмотреть ссылку, ответив простым текстовым сообщением на ссылку. В этом примере прикрепляется сообщение, повторяющее URL-адрес ссылки, соответствующий шаблону URL-адреса предварительного просмотра ссылки.

Node.js

узел/предварительный просмотр-ссылка/index.js
// Reply with a text message for URLs of the subdomain "text"
if (event.message.matchedUrl.url.includes("text.example.com")) {
  return {
    text: 'event.message.matchedUrl.url: ' + event.message.matchedUrl.url
  };
}

Питон

python/preview-link/main.py
# Reply with a text message for URLs of the subdomain "text"
if 'text.example.com' in event.get('message').get('matchedUrl').get('url'):
  return {
    'text': 'event.message.matchedUrl.url: ' +
            event.get('message').get('matchedUrl').get('url')
  }

Ява

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Reply with a text message for URLs of the subdomain "text"
if (event.at("/message/matchedUrl/url").asText().contains("text.example.com")) {
  return new Message().setText("event.message.matchedUrl.url: " +
    event.at("/message/matchedUrl/url").asText());
}

Скрипт приложений

приложения-script/preview-link/preview-link.gs
// Reply with a text message for URLs of the subdomain "text"
if (event.message.matchedUrl.url.includes("text.example.com")) {
  return {
    text: 'event.message.matchedUrl.url: ' + event.message.matchedUrl.url
  };
}

Чтобы прикрепить карточку к предварительно просматриваемой ссылке, верните ActionResponse типа UPDATE_USER_MESSAGE_CARDS . В этом примере прикрепляется базовая карта.

Приложение чата просматривает ссылку, прикрепив карточку к сообщению

Node.js

узел/предварительный просмотр-ссылка/index.js
// Attach a card to the message for URLs of the subdomain "support"
if (event.message.matchedUrl.url.includes("support.example.com")) {
  // A hard-coded card is used in this example. In a real-life scenario,
  // the case information would be fetched and used to build the card.
  return {
    actionResponse: { type: 'UPDATE_USER_MESSAGE_CARDS' },
    cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case basics',
        },
        sections: [{ widgets: [
          { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
          { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
          { decoratedText: { topLabel: 'Status', text: 'Open'}},
          { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
          { buttonList: { buttons: [{
            text: 'OPEN CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123'
            }},
          }, {
            text: 'RESOLVE CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123?resolved=y',
            }},
          }, {
            text: 'ASSIGN TO ME',
            onClick: { action: { function: 'assign'}}
          }]}}
        ]}]
      }
    }]
  };
}

Питон

python/preview-link/main.py
# Attach a card to the message for URLs of the subdomain "support"
if 'support.example.com' in event.get('message').get('matchedUrl').get('url'):
  # A hard-coded card is used in this example. In a real-life scenario,
  # the case information would be fetched and used to build the card.
  return {
    'actionResponse': { 'type': 'UPDATE_USER_MESSAGE_CARDS' },
    'cardsV2': [{
      'cardId': 'attachCard',
      'card': {
        'header': {
          'title': 'Example Customer Service Case',
          'subtitle': 'Case basics',
        },
        'sections': [{ 'widgets': [
          { 'decoratedText': { 'topLabel': 'Case ID', 'text': 'case123'}},
          { 'decoratedText': { 'topLabel': 'Assignee', 'text': 'Charlie'}},
          { 'decoratedText': { 'topLabel': 'Status', 'text': 'Open'}},
          { 'decoratedText': { 'topLabel': 'Subject', 'text': 'It won\'t turn on...' }},
          { 'buttonList': { 'buttons': [{
            'text': 'OPEN CASE',
            'onClick': { 'openLink': {
              'url': 'https://support.example.com/orders/case123'
            }},
          }, {
            'text': 'RESOLVE CASE',
            'onClick': { 'openLink': {
              'url': 'https://support.example.com/orders/case123?resolved=y',
            }},
          }, {
            'text': 'ASSIGN TO ME',
            'onClick': { 'action': { 'function': 'assign'}}
          }]}}
        ]}]
      }
    }]
  }

Ява

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Attach a card to the message for URLs of the subdomain "support"
if (event.at("/message/matchedUrl/url").asText().contains("support.example.com")) {
  // A hard-coded card is used in this example. In a real-life scenario,
  // the case information would be fetched and used to build the card.
  GoogleAppsCardV1CardHeader header = new GoogleAppsCardV1CardHeader();
  header.setTitle("Example Customer Service Case");
  header.setSubtitle("Case basics");

  GoogleAppsCardV1DecoratedText caseIdDecoratedText = new GoogleAppsCardV1DecoratedText();
  caseIdDecoratedText.setTopLabel("Case ID");
  caseIdDecoratedText.setText("case123");

  GoogleAppsCardV1Widget caseIdWidget = new GoogleAppsCardV1Widget();
  caseIdWidget.setDecoratedText(caseIdDecoratedText);

  GoogleAppsCardV1DecoratedText assigneeDecoratedText = new GoogleAppsCardV1DecoratedText();
  assigneeDecoratedText.setTopLabel("Assignee");
  assigneeDecoratedText.setText("Charlie");

  GoogleAppsCardV1Widget assigneeWidget = new GoogleAppsCardV1Widget();
  assigneeWidget.setDecoratedText(assigneeDecoratedText);

  GoogleAppsCardV1DecoratedText statusDecoratedText = new GoogleAppsCardV1DecoratedText();
  statusDecoratedText.setTopLabel("Status");
  statusDecoratedText.setText("Open");

  GoogleAppsCardV1Widget statusWidget = new GoogleAppsCardV1Widget();
  statusWidget.setDecoratedText(statusDecoratedText);

  GoogleAppsCardV1DecoratedText subjectDecoratedText = new GoogleAppsCardV1DecoratedText();
  subjectDecoratedText.setTopLabel("Subject");
  subjectDecoratedText.setText("It won't turn on...");

  GoogleAppsCardV1Widget subjectWidget = new GoogleAppsCardV1Widget();
  subjectWidget.setDecoratedText(subjectDecoratedText);

  GoogleAppsCardV1OpenLink openOpenLink = new GoogleAppsCardV1OpenLink();
  openOpenLink.setUrl("https://support.example.com/orders/case123");

  GoogleAppsCardV1OnClick openOnClick = new GoogleAppsCardV1OnClick();
  openOnClick.setOpenLink(openOpenLink);

  GoogleAppsCardV1Button openButton = new GoogleAppsCardV1Button();
  openButton.setText("OPEN CASE");
  openButton.setOnClick(openOnClick);

  GoogleAppsCardV1OpenLink resolveOpenLink = new GoogleAppsCardV1OpenLink();
  resolveOpenLink.setUrl("https://support.example.com/orders/case123?resolved=y");

  GoogleAppsCardV1OnClick resolveOnClick = new GoogleAppsCardV1OnClick();
  resolveOnClick.setOpenLink(resolveOpenLink);

  GoogleAppsCardV1Button resolveButton = new GoogleAppsCardV1Button();
  resolveButton.setText("RESOLVE CASE");
  resolveButton.setOnClick(resolveOnClick);

  GoogleAppsCardV1Action assignAction = new GoogleAppsCardV1Action();
  assignAction.setFunction("assign");

  GoogleAppsCardV1OnClick assignOnClick = new GoogleAppsCardV1OnClick();
  assignOnClick.setAction(assignAction);

  GoogleAppsCardV1Button assignButton = new GoogleAppsCardV1Button();
  assignButton.setText("ASSIGN TO ME");
  assignButton.setOnClick(assignOnClick);

  GoogleAppsCardV1ButtonList buttonList = new GoogleAppsCardV1ButtonList();
  buttonList.setButtons(List.of(openButton, resolveButton, assignButton));

  GoogleAppsCardV1Widget buttonListWidget = new GoogleAppsCardV1Widget();
  buttonListWidget.setButtonList(buttonList);

  GoogleAppsCardV1Section section = new GoogleAppsCardV1Section();
  section.setWidgets(List.of(caseIdWidget, assigneeWidget, statusWidget, subjectWidget, buttonListWidget));

  GoogleAppsCardV1Card card = new GoogleAppsCardV1Card();
  card.setHeader(header);
  card.setSections(List.of(section));

  GenericJson cardV2 = new GenericJson();
  cardV2.set("cardId", "attachCard");
  cardV2.set("card", card);

  GenericJson actionResponse = new GenericJson();
  actionResponse.set("type", "UPDATE_USER_MESSAGE_CARDS");

  GenericJson response = new GenericJson();
  response.set("actionResponse", actionResponse);
  response.set("cardsV2", List.of(cardV2));
  return response;
}

Скрипт приложений

В этом примере отправляется карточное сообщение, возвращая card JSON . Вы также можете воспользоваться карточной службой Apps Script .

приложения-script/preview-link/preview-link.gs
// Attach a card to the message for URLs of the subdomain "support"
if (event.message.matchedUrl.url.includes("support.example.com")) {
  // A hard-coded card is used in this example. In a real-life scenario,
  // the case information would be fetched and used to build the card.
  return {
    actionResponse: { type: 'UPDATE_USER_MESSAGE_CARDS' },
    cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case basics',
        },
        sections: [{ widgets: [
          { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
          { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
          { decoratedText: { topLabel: 'Status', text: 'Open'}},
          { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
          { buttonList: { buttons: [{
            text: 'OPEN CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123'
            }},
          }, {
            text: 'RESOLVE CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123?resolved=y',
            }},
          }, {
            text: 'ASSIGN TO ME',
            onClick: { action: { function: 'assign'}}
          }]}}
        ]}]
      }
    }]
  };
}

Ваше приложение Chat может обновлять карточку предварительного просмотра ссылки, когда пользователи взаимодействуют с ней, например нажимают кнопку на карточке.

Чтобы обновить карточку, ваше приложение чата должно обработать событие взаимодействия CARD_CLICKED и вернуть actionResponse в зависимости от того, кто отправил сообщение, содержащее предварительный просмотр ссылки:

  • Если сообщение отправил пользователь, установите для actionResponse.type значение UPDATE_USER_MESSAGE_CARDS .
  • Если приложение Chat отправило сообщение, установите для actionResponse.type значение UPDATE_MESSAGE .

Чтобы определить, кто отправил сообщение, вы можете использовать поле message.sender.type события взаимодействия, чтобы узнать, был ли отправитель пользователем HUMAN или BOT .

В следующем примере показано, как приложение чата обновляет предварительный просмотр ссылки всякий раз, когда пользователь нажимает кнопку «Назначить мне» , обновляя поле «Назначенный» карты и отключая кнопку.

Приложение чата просматривает ссылку с обновленной версией карточки, прикрепленной к сообщению.

Node.js

узел/предварительный просмотр-ссылка/index.js
/**
 * Updates a card that was attached to a message with a previewed link.
 *
 * @param {Object} event The event object from Chat.
 *
 * @return {Object} Response from the Chat app. Either a new card attached to
 * the message with the previewed link, or an update to an existing card.
 */
function onCardClick(event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.action.actionMethodName === 'assign') {
    // A hard-coded card is used in this example. In a real-life scenario,
    // an actual assign action would be performed before building the card.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    const actionResponseType = event.message.sender.type === 'HUMAN' ?
      'UPDATE_USER_MESSAGE_CARDS' :
      'UPDATE_MESSAGE';

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return {
      actionResponse: { type: actionResponseType },
      cardsV2: [{
        cardId: 'attachCard',
        card: {
          header: {
            title: 'Example Customer Service Case',
            subtitle: 'Case basics',
          },
          sections: [{ widgets: [
            { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
            // The assignee is now "You"
            { decoratedText: { topLabel: 'Assignee', text: 'You'}},
            { decoratedText: { topLabel: 'Status', text: 'Open'}},
            { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
            { buttonList: { buttons: [{
              text: 'OPEN CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123'
              }},
            }, {
              text: 'RESOLVE CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123?resolved=y',
              }},
            }, {
              text: 'ASSIGN TO ME',
              // The button is now disabled
              disabled: true,
              onClick: { action: { function: 'assign'}}
            }]}}
          ]}]
        }
      }]
    };
  }
}

Питон

python/preview-link/main.py
def on_card_click(event: dict) -> dict:
  """Updates a card that was attached to a message with a previewed link."""
  # To respond to the correct button, checks the button's actionMethodName.
  if 'assign' == event.get('action').get('actionMethodName'):
    # A hard-coded card is used in this example. In a real-life scenario,
    # an actual assign action would be performed before building the card.

    # Checks whether the message event originated from a human or a Chat app
    # and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    # "UPDATE_MESSAGE" if Chat app.
    actionResponseType = 'UPDATE_USER_MESSAGE_CARDS' if \
      event.get('message').get('sender').get('type') == 'HUMAN' else \
      'UPDATE_MESSAGE'

    # Returns the updated card that displays "You" for the assignee
    # and that disables the button.
    return {
      'actionResponse': { 'type': actionResponseType },
      'cardsV2': [{
        'cardId': 'attachCard',
        'card': {
          'header': {
            'title': 'Example Customer Service Case',
            'subtitle': 'Case basics',
          },
          'sections': [{ 'widgets': [
            { 'decoratedText': { 'topLabel': 'Case ID', 'text': 'case123'}},
            # The assignee is now "You"
            { 'decoratedText': { 'topLabel': 'Assignee', 'text': 'You'}},
            { 'decoratedText': { 'topLabel': 'Status', 'text': 'Open'}},
            { 'decoratedText': { 'topLabel': 'Subject', 'text': 'It won\'t turn on...' }},
            { 'buttonList': { 'buttons': [{
              'text': 'OPEN CASE',
              'onClick': { 'openLink': {
                'url': 'https://support.example.com/orders/case123'
              }},
            }, {
              'text': 'RESOLVE CASE',
              'onClick': { 'openLink': {
                'url': 'https://support.example.com/orders/case123?resolved=y',
              }},
            }, {
              'text': 'ASSIGN TO ME',
              # The button is now disabled
              'disabled': True,
              'onClick': { 'action': { 'function': 'assign'}}
            }]}}
          ]}]
        }
      }]
    }

Ява

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Updates a card that was attached to a message with a previewed link.
GenericJson onCardClick(JsonNode event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.at("/action/actionMethodName").asText().equals("assign")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // an actual assign action would be performed before building the card.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    String actionResponseType =
      event.at("/message/sender/type").asText().equals("HUMAN")
      ? "UPDATE_USER_MESSAGE_CARDS" : "UPDATE_MESSAGE";

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    GoogleAppsCardV1CardHeader header = new GoogleAppsCardV1CardHeader();
    header.setTitle("Example Customer Service Case");
    header.setSubtitle("Case basics");

    GoogleAppsCardV1DecoratedText caseIdDecoratedText = new GoogleAppsCardV1DecoratedText();
    caseIdDecoratedText.setTopLabel("Case ID");
    caseIdDecoratedText.setText("case123");

    GoogleAppsCardV1Widget caseIdWidget = new GoogleAppsCardV1Widget();
    caseIdWidget.setDecoratedText(caseIdDecoratedText);

    GoogleAppsCardV1DecoratedText assigneeDecoratedText = new GoogleAppsCardV1DecoratedText();
    assigneeDecoratedText.setTopLabel("Assignee");
    // The assignee is now "You"
    assigneeDecoratedText.setText("You");

    GoogleAppsCardV1Widget assigneeWidget = new GoogleAppsCardV1Widget();
    assigneeWidget.setDecoratedText(assigneeDecoratedText);

    GoogleAppsCardV1DecoratedText statusDecoratedText = new GoogleAppsCardV1DecoratedText();
    statusDecoratedText.setTopLabel("Status");
    statusDecoratedText.setText("Open");

    GoogleAppsCardV1Widget statusWidget = new GoogleAppsCardV1Widget();
    statusWidget.setDecoratedText(statusDecoratedText);

    GoogleAppsCardV1DecoratedText subjectDecoratedText = new GoogleAppsCardV1DecoratedText();
    subjectDecoratedText.setTopLabel("Subject");
    subjectDecoratedText.setText("It won't turn on...");

    GoogleAppsCardV1Widget subjectWidget = new GoogleAppsCardV1Widget();
    subjectWidget.setDecoratedText(subjectDecoratedText);

    GoogleAppsCardV1OpenLink openOpenLink = new GoogleAppsCardV1OpenLink();
    openOpenLink.setUrl("https://support.example.com/orders/case123");

    GoogleAppsCardV1OnClick openOnClick = new GoogleAppsCardV1OnClick();
    openOnClick.setOpenLink(openOpenLink);

    GoogleAppsCardV1Button openButton = new GoogleAppsCardV1Button();
    openButton.setText("OPEN CASE");
    openButton.setOnClick(openOnClick);

    GoogleAppsCardV1OpenLink resolveOpenLink = new GoogleAppsCardV1OpenLink();
    resolveOpenLink.setUrl("https://support.example.com/orders/case123?resolved=y");

    GoogleAppsCardV1OnClick resolveOnClick = new GoogleAppsCardV1OnClick();
    resolveOnClick.setOpenLink(resolveOpenLink);

    GoogleAppsCardV1Button resolveButton = new GoogleAppsCardV1Button();
    resolveButton.setText("RESOLVE CASE");
    resolveButton.setOnClick(resolveOnClick);

    GoogleAppsCardV1Action assignAction = new GoogleAppsCardV1Action();
    assignAction.setFunction("assign");

    GoogleAppsCardV1OnClick assignOnClick = new GoogleAppsCardV1OnClick();
    assignOnClick.setAction(assignAction);

    GoogleAppsCardV1Button assignButton = new GoogleAppsCardV1Button();
    assignButton.setText("ASSIGN TO ME");
    // The button is now disabled
    assignButton.setDisabled(true);
    assignButton.setOnClick(assignOnClick);

    GoogleAppsCardV1ButtonList buttonList = new GoogleAppsCardV1ButtonList();
    buttonList.setButtons(List.of(openButton, resolveButton, assignButton));

    GoogleAppsCardV1Widget buttonListWidget = new GoogleAppsCardV1Widget();
    buttonListWidget.setButtonList(buttonList);

    GoogleAppsCardV1Section section = new GoogleAppsCardV1Section();
    section.setWidgets(List.of(caseIdWidget, assigneeWidget, statusWidget, subjectWidget, buttonListWidget));

    GoogleAppsCardV1Card card = new GoogleAppsCardV1Card();
    card.setHeader(header);
    card.setSections(List.of(section));

    GenericJson cardV2 = new GenericJson();
    cardV2.set("cardId", "attachCard");
    cardV2.set("card", card);

    GenericJson actionResponse = new GenericJson();
    actionResponse.set("type", actionResponseType);

    GenericJson response = new GenericJson();
    response.set("actionResponse", actionResponse);
    response.set("cardsV2", List.of(cardV2));
    return response;
  }
  return new GenericJson();
}

Скрипт приложений

В этом примере отправляется карточное сообщение, возвращая card JSON . Вы также можете использовать сервис карточек Apps Script .

приложения-script/preview-link/preview-link.gs
/**
 * Updates a card that was attached to a message with a previewed link.
 *
 * @param {Object} event The event object from Chat.
 *
 * @return {Object} Response from the Chat app. Either a new card attached to
 * the message with the previewed link, or an update to an existing card.
 */
function onCardClick(event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.action.actionMethodName === 'assign') {
    // A hard-coded card is used in this example. In a real-life scenario,
    // an actual assign action would be performed before building the card.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    const actionResponseType = event.message.sender.type === 'HUMAN' ?
      'UPDATE_USER_MESSAGE_CARDS' :
      'UPDATE_MESSAGE';

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return {
      actionResponse: { type: actionResponseType },
      cardsV2: [{
        cardId: 'attachCard',
        card: {
          header: {
            title: 'Example Customer Service Case',
            subtitle: 'Case basics',
          },
          sections: [{ widgets: [
            { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
            // The assignee is now "You"
            { decoratedText: { topLabel: 'Assignee', text: 'You'}},
            { decoratedText: { topLabel: 'Status', text: 'Open'}},
            { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
            { buttonList: { buttons: [{
              text: 'OPEN CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123'
              }},
            }, {
              text: 'RESOLVE CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123?resolved=y',
              }},
            }, {
              text: 'ASSIGN TO ME',
              // The button is now disabled
              disabled: true,
              onClick: { action: { function: 'assign'}}
            }]}}
          ]}]
        }
      }]
    };
  }
}

Ограничения и соображения

При настройке предварительного просмотра ссылок для приложения Chat обратите внимание на следующие ограничения и рекомендации:

  • Каждое приложение чата поддерживает предварительный просмотр ссылок до 5 шаблонов URL-адресов.
  • Приложения чата просматривают одну ссылку на каждое сообщение. Если в одном сообщении присутствует несколько доступных для предварительного просмотра ссылок, отображается только первая доступная для предварительного просмотра ссылка.
  • Приложения чата просматривают только ссылки, начинающиеся с https:// , поэтому https://support.example.com/cases/ являются предварительным просмотром, а support.example.com/cases/ нет.
  • Если сообщение не содержит другую информацию, которая отправляется в приложение Chat, например косую черту , в приложение Chat посредством предварительного просмотра ссылки отправляется только URL-адрес ссылки.
  • Если пользователь публикует ссылку, приложение Chat может обновить карточку предварительного просмотра ссылки только в том случае, если пользователи взаимодействуют с карточкой, например при нажатии кнопки. Вы не можете вызвать метод update() API Chat для ресурса Message , чтобы асинхронно обновить сообщение пользователя.
  • Приложения чата должны просматривать ссылки для всех в пространстве, поэтому в сообщении должно быть опущено поле privateMessageViewer .

При реализации предварительного просмотра ссылок вам может потребоваться отладка приложения Chat, прочитав журналы приложения. Чтобы прочитать журналы, посетите Logs Explorer в консоли Google Cloud.