Добавляйте интерактивные элементы пользовательского интерфейса на карточки.

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

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

  • Сообщения , содержащие одну или несколько карточек.
  • Домашние страницы — карточка, которая появляется на вкладке «Главная» в личных сообщениях в приложении Chat.
  • Диалоги — карточки, которые открываются в новом окне из сообщений и домашних страниц.

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


Используйте конструктор карточек для разработки и предварительного просмотра сообщений и пользовательских интерфейсов для приложений чата:

Откройте конструктор карточек

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

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

Добавить кнопку

Виджет ButtonList отображает набор кнопок. Кнопки могут отображать текст, значок или и текст, и значок. Каждая Button поддерживает действие OnClick , которое происходит, когда пользователи нажимают кнопку. Например:

  • Откройте гиперссылку с помощью OpenLink , чтобы предоставить пользователям дополнительную информацию.
  • Запустите action , которое запускает пользовательскую функцию, например вызов API.

Для удобства кнопки поддерживают альтернативный текст.

Добавьте кнопку, которая запускает пользовательскую функцию

Ниже представлена ​​карточка, состоящая из виджета ButtonList с двумя кнопками. Одна кнопка открывает документацию для разработчиков Google Chat на новой вкладке. Другая кнопка запускает пользовательскую функцию goToView() и передает параметр viewType="BIRD EYE VIEW" .

Добавьте кнопку в стиле Material Design.

Ниже показан набор кнопок в различных стилях кнопок Material Design.

Чтобы применить стиль Material Design, не включайте атрибут «цвет».

Добавьте кнопку произвольного цвета и деактивированную кнопку.

Вы можете запретить пользователям нажимать кнопку, установив "disabled": "true" .

Ниже показана карточка, состоящая из виджета ButtonList с двумя кнопками. Одна кнопка использует поле Color для настройки цвета фона кнопки. Другая кнопка деактивирована с помощью поля Disabled , что не позволяет пользователю нажать кнопку и выполнить функцию.

Добавляем кнопку со значком

Ниже показана карточка, состоящая из виджета ButtonList с двумя виджетами Button со значками. Одна кнопка использует knownIcon для отображения встроенного значка электронной почты Google Chat. Другая кнопка использует поле iconUrl для отображения пользовательского виджета значка .

Добавьте кнопку со значком и текстом

Ниже показана карточка, состоящая из виджета ButtonList , который предлагает пользователю отправить электронное письмо. На первой кнопке отображается значок электронной почты, а на второй — текст. Пользователь может щелкнуть значок или текстовую кнопку, чтобы запустить функцию sendEmail .

Настройте кнопку для сворачиваемого раздела

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

Добавить меню переполнения

Overflow menu можно использовать в карточках чата, чтобы предлагать дополнительные параметры и действия. Это позволяет вам включать больше опций, не загромождая интерфейс карты, обеспечивая чистый и организованный дизайн.

Добавить список фишек

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

Собирайте информацию от пользователей

В этом разделе объясняется, как можно добавлять виджеты, собирающие информацию, например текст или выделенные фрагменты.

Чтобы узнать, как обрабатывать вводимые пользователями данные, см. раздел Сбор и обработка информации от пользователей Google Chat .

Собрать текст

Виджет TextInput предоставляет поле, в котором пользователи могут вводить текст. Виджет поддерживает предложения, которые помогают пользователям вводить унифицированные данные, и действия при изменении, которые представляют собой Actions , которые выполняются при изменении в поле ввода текста, например, когда пользователь добавляет или удаляет текст.

Если вам нужно собрать абстрактные или неизвестные данные от пользователей, используйте этот виджет TextInput . Чтобы собрать определенные данные от пользователей, используйте вместо этого виджет SelectionInput .

Ниже представлена ​​карточка, состоящая из виджета TextInput :

Соберите даты или время

Виджет DateTimePicker позволяет пользователям вводить дату, время или дату и время одновременно. Или пользователи могут использовать средство выбора для выбора даты и времени. Если пользователи вводят неверную дату или время, средство выбора отображает ошибку, которая предлагает пользователям ввести информацию правильно.

Ниже показана карточка, состоящая из трех разных типов виджетов DateTimePicker :

Разрешить пользователям выбирать элементы

Виджет SelectionInput предоставляет набор выбираемых элементов, таких как флажки, переключатели, переключатели или раскрывающееся меню. Вы можете использовать этот виджет для сбора определенных и стандартизированных данных от пользователей. Чтобы собрать неопределенные данные от пользователей, используйте вместо этого виджет TextInput .

Виджет SelectionInput поддерживает предложения, которые помогают пользователям вводить унифицированные данные, и действия при изменении, которые представляют собой Actions , которые выполняются, когда происходит изменение в поле ввода выбора, например, когда пользователь выбирает или отменяет выбор элемента.

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

В этом разделе приведены примеры карточек, использующих виджет SelectionInput . В примерах используются разные типы входных данных раздела:

Добавить флажок

Ниже показана карточка, в которой пользователю предлагается указать, является ли контакт профессиональным, личным или и тем, и другим, с помощью виджета SelectionInput , в котором используются флажки:

Добавить переключатель

Ниже показана карточка, в которой пользователю предлагается указать, является ли контакт профессиональным или личным, с помощью виджета SelectionInput , использующего переключатели:

Добавить переключатель

Ниже показана карточка, в которой пользователю предлагается указать, является ли контакт профессиональным, личным или и тем, и другим, с помощью виджета SelectionInput , использующего переключатели:

Ниже показана карточка, в которой пользователю предлагается указать, является ли контакт профессиональным или личным, с помощью виджета SelectionInput , использующего раскрывающееся меню:

Добавить меню с множественным выбором

Ниже показана карточка, предлагающая пользователю выбрать контакты из меню с множественным выбором:

Вы можете заполнить элементы для меню с множественным выбором из следующих источников данных в Google Workspace:

  • Пользователи Google Workspace . Вы можете добавлять пользователей только в пределах одной организации Google Workspace.
  • Пространства чата . Пользователь, вводящий элементы в меню с множественным выбором, может просматривать и выбирать только пространства, к которым они принадлежат, в своей организации Google Workspace.

Чтобы использовать источники данных Google Workspace, вы указываете поле platformDataSource . В отличие от других типов входных данных выбора, вы опускаете объекты SectionItem , поскольку эти элементы выбора динамически получаются из Google Workspace.

Следующий код показывает меню с множественным выбором пользователей Google Workspace. Чтобы заполнить пользователей, вход выбора устанавливает commonDataSource в USER :

JSON

{
  "selectionInput": {
    "name": "contacts",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 5,
    "multiSelectMinQueryLength": 1,
    "platformDataSource": {
      "commonDataSource": "USER"
    }
  }
}

Следующий код показывает меню с множественным выбором пространств чата. Для заполнения пробелов входные данные выбора указывают поле hostAppDataSource . Меню множественного выбора также устанавливает для defaultToCurrentSpace значение true , что делает текущее пространство выбором по умолчанию в меню:

JSON

{
  "selectionInput": {
    "name": "spaces",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 3,
    "multiSelectMinQueryLength": 1,
    "platformDataSource": {
      "hostAppDataSource": {
        "chatDataSource": {
          "spaceDataSource": {
            "defaultToCurrentSpace": true
          }
        }
      }
    }
  }
}

В меню с множественным выбором также можно заполнять элементы из стороннего или внешнего источника данных. Например, вы можете использовать меню с множественным выбором, чтобы помочь пользователю выбрать из списка потенциальных клиентов из системы управления взаимоотношениями с клиентами (CRM).

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

Чтобы уменьшить количество запросов к внешнему источнику данных, вы можете включить предлагаемые элементы, которые появляются в меню с множественным выбором до того, как пользователи введут его в меню. Например, вы можете заполнить для пользователя недавно найденные контакты. Чтобы заполнить предложенные элементы из внешнего источника данных, укажите объекты SelectionItem .

Следующий код показывает меню с множественным выбором элементов из внешнего набора контактов пользователя. По умолчанию в меню отображается один контакт и запускается функция getContacts для получения и заполнения элементов из внешнего источника данных:

Node.js

узел/выбор-вход/index.js
selectionInput: {
  name: "contacts",
  type: "MULTI_SELECT",
  label: "Selected contacts",
  multiSelectMaxSelectedItems: 3,
  multiSelectMinQueryLength: 1,
  externalDataSource: { function: "getContacts" },
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  items: [getContact("3")]
}

Питон

python/выбор-вход/main.py
'selectionInput': {
  'name': "contacts",
  'type': "MULTI_SELECT",
  'label': "Selected contacts",
  'multiSelectMaxSelectedItems': 3,
  'multiSelectMinQueryLength': 1,
  'externalDataSource': { 'function': "getContacts" },
  # Suggested items loaded by default.
  # The list is static here but it could be dynamic.
  'items': [get_contact("3")]
}

Ява

java/selection-input/src/main/java/com/google/chat/selectionInput/App.java
.setSelectionInput(new GoogleAppsCardV1SelectionInput()
  .setName("contacts")
  .setType("MULTI_SELECT")
  .setLabel("Selected contacts")
  .setMultiSelectMaxSelectedItems(3)
  .setMultiSelectMinQueryLength(1)
  .setExternalDataSource(new GoogleAppsCardV1Action().setFunction("getContacts"))
  .setItems(List.of(getContact("3")))))))))));

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

приложения-скрипт/выбор-input/выбор-input.gs
selectionInput: {
  name: "contacts",
  type: "MULTI_SELECT",
  label: "Selected contacts",
  multiSelectMaxSelectedItems: 3,
  multiSelectMinQueryLength: 1,
  externalDataSource: { function: "getContacts" },
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  items: [getContact("3")]
}

Для внешних источников данных вы также можете автозаполнять элементы, которые пользователи начинают вводить в меню с множественным выбором. Например, если пользователь начинает вводить Atl для меню, в котором представлены города в США, ваше приложение Chat может автоматически предложить Atlanta до того, как пользователь завершит ввод. Вы можете автозаполнить до 100 элементов.

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

  • Передайте объект события, который представляет взаимодействие пользователя с меню.
  • Определите, что значение invokedFunction события взаимодействия соответствует функции из поля externalDataSource .
  • Если функции совпадают, возвращайте предложенные элементы из внешнего источника данных. Чтобы предлагать элементы на основе того, что вводит пользователь, получите значение ключа autocomplete_widget_query . Это значение представляет то, что пользователь вводит в меню.

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

Node.js

узел/выбор-вход/index.js
/**
 * Responds to a WIDGET_UPDATE event in Google Chat.
 *
 * @param {Object} event The event object from Chat API.
 * @return {Object} Response from the Chat app.
 */
function onWidgetUpdate(event) {
  if (event.common["invokedFunction"] === "getContacts") {
    const query = event.common.parameters["autocomplete_widget_query"];
    return { actionResponse: {
      type: "UPDATE_WIDGET",
      updatedWidget: { suggestions: { items: [
        // The list is static here but it could be dynamic.
        getContact("1"), getContact("2"), getContact("3"), getContact("4"), getContact("5")
      // Only return items based on the query from the user
      ].filter(e => !query || e.text.includes(query))}}
    }};
  }
}

/**
 * Generate a suggested contact given an ID.
 *
 * @param {String} id The ID of the contact to return.
 * @return {Object} The contact formatted as a suggested item for selectors.
 */
function getContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}

Питон

python/выбор-вход/main.py
def on_widget_update(event: dict) -> dict:
  """Responds to a WIDGET_UPDATE event in Google Chat."""
  if "getContacts" == event.get("common").get("invokedFunction"):
    query = event.get("common").get("parameters").get("autocomplete_widget_query")
    return { 'actionResponse': {
      'type': "UPDATE_WIDGET",
      'updatedWidget': { 'suggestions': { 'items': list(filter(lambda e: query is None or query in e["text"], [
        # The list is static here but it could be dynamic.
        get_contact("1"), get_contact("2"), get_contact("3"), get_contact("4"), get_contact("5")
      # Only return items based on the query from the user
      ]))}}
    }}


def get_contact(id: str) -> dict:
  """Generate a suggested contact given an ID."""
  return {
    'value': id,
    'startIconUri': "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    'text': "Contact " + id
  }

Ява

java/selection-input/src/main/java/com/google/chat/selectionInput/App.java
// Responds to a WIDGET_UPDATE event in Google Chat.
Message onWidgetUpdate(JsonNode event) {
  if ("getContacts".equals(event.at("/invokedFunction").asText())) {
    String query = event.at("/common/parameters/autocomplete_widget_query").asText();
    return new Message().setActionResponse(new ActionResponse()
      .setType("UPDATE_WIDGET")
      .setUpdatedWidget(new UpdatedWidget()
        .setSuggestions(new SelectionItems().setItems(List.of(
          // The list is static here but it could be dynamic.
          getContact("1"), getContact("2"), getContact("3"), getContact("4"), getContact("5")
        // Only return items based on the query from the user
        ).stream().filter(e -> query == null || e.getText().indexOf(query) > -1).toList()))));
  }
  return null;
}

// Generate a suggested contact given an ID.
GoogleAppsCardV1SelectionItem getContact(String id) {
  return new GoogleAppsCardV1SelectionItem()
    .setValue(id)
    .setStartIconUri("https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png")
    .setText("Contact " + id);
}

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

приложения-скрипт/выбор-input/выбор-input.gs
/**
 * Responds to a WIDGET_UPDATE event in Google Chat.
 *
 * @param {Object} event The event object from Chat API.
 * @return {Object} Response from the Chat app.
 */
function onWidgetUpdate(event) {
  if (event.common["invokedFunction"] === "getContacts") {
    const query = event.common.parameters["autocomplete_widget_query"];
    return { actionResponse: {
      type: "UPDATE_WIDGET",
      updatedWidget: { suggestions: { items: [
        // The list is static here but it could be dynamic.
        getContact("1"), getContact("2"), getContact("3"), getContact("4"), getContact("5")
      // Only return items based on the query from the user
      ].filter(e => !query || e.text.includes(query))}}
    }};
  }
}

/**
 * Generate a suggested contact given an ID.
 *
 * @param {String} id The ID of the contact to return.
 * @return {Object} The contact formatted as a suggested item for selectors.
 */
function getContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}

Проверка данных, введенных в карты

На этой странице объясняется, как проверить данные, введенные в action карты и виджеты. Например, вы можете проверить, что поле ввода текста содержит текст, введенный пользователем, или что оно содержит определенное количество символов.

Установите необходимые виджеты для действий

В рамках action карточки добавьте названия виджетов, которые нужны действию, в список requiredWidgets .

Если какие-либо виджеты, перечисленные здесь, не имеют значения при вызове этого действия, то отправка действия формы отменяется.

Если для действия установлено "all_widgets_are_required": "true" , то для этого действия требуются все виджеты на карточке.

Установите действие all_widgets_are_required в множественном выборе

JSON

{
  "sections": [
    {
      "header": "Select contacts",
      "widgets": [
        {
          "selectionInput": {
            "type": "MULTI_SELECT",
            "label": "Selected contacts",
            "name": "contacts",
            "multiSelectMaxSelectedItems": 3,
            "multiSelectMinQueryLength": 1,
            "onChangeAction": {
              "all_widgets_are_required": true
            },
            "items": [
              {
                "value": "contact-1",
                "startIconUri": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
                "text": "Contact 1",
                "bottomText": "Contact one description",
                "selected": false
              },
              {
                "value": "contact-2",
                "startIconUri": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
                "text": "Contact 2",
                "bottomText": "Contact two description",
                "selected": false
              },
              {
                "value": "contact-3",
                "startIconUri": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
                "text": "Contact 3",
                "bottomText": "Contact three description",
                "selected": false
              },
              {
                "value": "contact-4",
                "startIconUri": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
                "text": "Contact 4",
                "bottomText": "Contact four description",
                "selected": false
              },
              {
                "value": "contact-5",
                "startIconUri": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
                "text": "Contact 5",
                "bottomText": "Contact five description",
                "selected": false
              }
            ]
          }
        }
      ]
    }
  ]
}
Установите действие all_widgets_are_required в dateTimePicker.

JSON

{
  "sections": [
    {
      "widgets": [
        {
          "textParagraph": {
            "text": "A datetime picker widget with both date and time:"
          }
        },
        {
          "divider": {}
        },
        {
          "dateTimePicker": {
            "name": "date_time_picker_date_and_time",
            "label": "meeting",
            "type": "DATE_AND_TIME"
          }
        },
        {
          "textParagraph": {
            "text": "A datetime picker widget with just date:"
          }
        },
        {
          "divider": {}
        },
        {
          "dateTimePicker": {
            "name": "date_time_picker_date_only",
            "label": "Choose a date",
            "type": "DATE_ONLY",
            "onChangeAction":{
              "all_widgets_are_required": true
            }
          }
        },
        {
          "textParagraph": {
            "text": "A datetime picker widget with just time:"
          }
        },
        {
          "divider": {}
        },
        {
          "dateTimePicker": {
            "name": "date_time_picker_time_only",
            "label": "Select a time",
            "type": "TIME_ONLY"
          }
        }
      ]
    }
  ]
}
Установите действие all_widgets_are_required в раскрывающемся меню.

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "collapsible": true,
      "uncollapsibleWidgetsCount": 1,
      "widgets": [
        {
          "selectionInput": {
            "name": "location",
            "label": "Select Color",
            "type": "DROPDOWN",
            "onChangeAction": {
              "all_widgets_are_required": true
            },
            "items": [
              {
                "text": "Red",
                "value": "red",
                "selected": false
              },
              {
                "text": "Green",
                "value": "green",
                "selected": false
              },
              {
                "text": "White",
                "value": "white",
                "selected": false
              },
              {
                "text": "Blue",
                "value": "blue",
                "selected": false
              },
              {
                "text": "Black",
                "value": "black",
                "selected": false
              }
            ]
          }
        }
      ]
    }
  ]
}

Установите проверку для виджета ввода текста

В поле проверки виджета textInput можно указать ограничение на количество символов и тип ввода для этого виджета ввода текста.

Установите ограничение на количество символов для виджета ввода текста

JSON

{
  "sections": [
    {
      "header": "Tell us about yourself",
      "collapsible": true,
      "uncollapsibleWidgetsCount": 2,
      "widgets": [
        {
          "textInput": {
            "name": "favoriteColor",
            "label": "Favorite color",
            "type": "SINGLE_LINE",
            "validation": {"character_limit":15},
            "onChangeAction":{
              "all_widgets_are_required": true
            }
          }
        }
      ]
    }
  ]
}
Установите тип ввода для виджета ввода текста

JSON

{
  "sections": [
    {
      "header": "Validate text inputs by input types",
      "collapsible": true,
      "uncollapsibleWidgetsCount": 2,
      "widgets": [
        {
          "textInput": {
            "name": "mailing_address",
            "label": "Please enter a valid email address",
            "type": "SINGLE_LINE",
            "validation": {
              "input_type": "EMAIL"
            },
            "onChangeAction": {
              "all_widgets_are_required": true
            }
          }
        },
        {
          "textInput": {
            "name": "validate_integer",
            "label": "Please enter a number",
              "type": "SINGLE_LINE",
            "validation": {
              "input_type": "INTEGER"
            }
          }
        },
        {
          "textInput": {
            "name": "validate_float",
            "label": "Please enter a number with a decimal",
            "type": "SINGLE_LINE",
            "validation": {
              "input_type": "FLOAT"
            }
          }
        }
      ]
    }
  ]
}

Устранение неполадок

Когда приложение или карточка Google Chat возвращает ошибку, в интерфейсе Chat отображается сообщение «Что-то пошло не так». или «Невозможно обработать ваш запрос». Иногда в пользовательском интерфейсе чата не отображается сообщение об ошибке, но приложение или карточка чата выдает неожиданный результат; например, сообщение с карточкой может не появиться.

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