Dodawanie interaktywnych elementów interfejsu do kart

Na tej stronie dowiesz się, jak dodawać do kart widżety i elementy interfejsu, aby użytkownicy mogli wchodzić w interakcje z Twoją aplikacją do obsługi czatu w Google, np. klikać przyciski lub przesyłać informacje.

Aplikacje do obsługi czatu mogą używać tych interfejsów Google Chat do tworzenia interaktywnych kart:

  • Wiadomości zawierające co najmniej 1 kartę.
  • Strony główne, czyli karty wyświetlane na karcie Strona główna w czatach z aplikacją Google Chat.
  • Okna, czyli karty, które otwierają się w nowym oknie z wiadomości i stron głównych.

Gdy użytkownicy wchodzą w interakcję z kartami, aplikacje Google Chat mogą używać otrzymanych danych do przetwarzania i odpowiedniego reagowania. Szczegółowe informacje znajdziesz w artykule Zbieranie i przetwarzanie informacji od użytkowników Google Chat.


Użyj narzędzia do tworzenia kart, aby projektować i wyświetlać podgląd wiadomości oraz interfejsów użytkownika w aplikacjach do obsługi czatu:

Otwórz narzędzie do tworzenia kart

Wymagania wstępne

Aplikacja Google Chat skonfigurowana do odbierania interakcji użytkowników i odpowiadania na nie. Aby utworzyć interaktywną aplikację do obsługi czatu, wykonaj jeden z tych przewodników Szybki start, w zależności od architektury aplikacji, której chcesz użyć:

Dodawanie przycisku

ButtonListWidżet wyświetla zestaw przycisków. Przyciski mogą wyświetlać tekst, ikonę lub tekst i ikonę. Każdy element Button obsługuje OnClickdziałanie wykonywane, gdy użytkownicy klikną przycisk. Na przykład:

  • Otwórz hiperlink za pomocą symbolu OpenLink, aby przekazać użytkownikom dodatkowe informacje.
  • Uruchom action, która uruchamia funkcję niestandardową, np. wywołuje interfejs API.

Przyciski obsługują tekst alternatywny, co ułatwia korzystanie z nich osobom z niepełnosprawnościami.

Dodawanie przycisku, który uruchamia funkcję niestandardową

Poniżej znajduje się karta składająca się z widżetu ButtonList z 2 przyciskami. Jeden przycisk otwiera dokumentację dla deweloperów Google Chat w nowej karcie. Drugi przycisk uruchamia funkcję niestandardową o nazwie goToView() i przekazuje parametr viewType="BIRD EYE VIEW".

Dodawanie przycisku w stylu Material Design

Poniżej znajdziesz zestaw przycisków w różnych stylach przycisków Material Design.

Aby zastosować styl Material Design, nie uwzględniaj atrybutu „color”.

Dodawanie przycisku z kolorem niestandardowym i przycisku dezaktywowanego

Możesz uniemożliwić użytkownikom kliknięcie przycisku, ustawiając wartość "disabled": "true".

Poniżej znajduje się karta składająca się z widżetu ButtonList z 2 przyciskami. Jeden przycisk korzysta z pola Color, aby dostosować kolor tła przycisku. Drugi przycisk jest dezaktywowany za pomocą pola Disabled, co uniemożliwia użytkownikowi kliknięcie przycisku i wykonanie funkcji.

Dodawanie przycisku z ikoną

Poniżej znajduje się karta składająca się z widżetu ButtonList z 2 widżetami ikon Button. Jeden przycisk używa pola knownIcon do wyświetlania wbudowanej ikony e-maila Google Chat. Drugi przycisk używa pola iconUrl do wyświetlania widżetu z ikoną niestandardową.

Dodawanie przycisku z ikoną i tekstem

Poniżej znajduje się karta z widżetem ButtonList, który wyświetla użytkownikowi prośbę o wysłanie e-maila. Pierwszy przycisk wyświetla ikonę e-maila, a drugi – tekst. Użytkownik może kliknąć ikonę lub tekst przycisku, aby uruchomić funkcję sendEmail.

Dostosowywanie przycisku sekcji zwijanej

Dostosuj przycisk sterowania, który zwija i rozwija sekcje w karcie. Wybierz jedną z wielu ikon lub obrazów, aby wizualnie przedstawić zawartość sekcji, co ułatwi użytkownikom zrozumienie informacji i interakcję z nimi.

Dodawanie rozszerzonego menu

Element Overflow menu można stosować na kartach Google Chat, aby oferować dodatkowe opcje i działania. Umożliwia to dodanie większej liczby opcji bez zaśmiecania interfejsu karty, co zapewnia przejrzysty i uporządkowany wygląd.

Dodawanie listy elementów

Widżet ChipList to wszechstronny i atrakcyjny wizualnie sposób wyświetlania informacji. Używaj list przycisków, aby przedstawiać tagi, kategorie lub inne istotne dane, co ułatwi użytkownikom poruszanie się po Twoich treściach i wchodzenie z nimi w interakcje.

Zbieranie informacji od użytkowników

Z tej sekcji dowiesz się, jak dodawać widżety, które zbierają informacje, np. tekst lub wybrane opcje.

Aby dowiedzieć się, jak przetwarzać dane wprowadzane przez użytkowników, przeczytaj artykuł Zbieranie i przetwarzanie informacji od użytkowników Google Chat.

Zbieranie tekstu

Widżet TextInput udostępnia pole, w którym użytkownicy mogą wpisywać tekst. Widżet obsługuje sugestie, które pomagają użytkownikom wprowadzać jednolite dane, oraz działania po zmianie, które są Actions wykonywane, gdy w polu do wprowadzania danych nastąpi zmiana, np. użytkownik doda lub usunie tekst.

Jeśli musisz zbierać od użytkowników abstrakcyjne lub nieznane dane, użyj tego widżetuTextInput. Aby zbierać określone dane od użytkowników, użyj widżetu SelectionInput.

Poniżej znajdziesz kartę z widżetem TextInput:

Zbieranie dat lub godzin

DateTimePickerWidżet umożliwia użytkownikom wprowadzanie daty, godziny lub daty i godziny. Użytkownicy mogą też używać selektora do wybierania dat i godzin. Jeśli użytkownicy wpiszą nieprawidłową datę lub godzinę, selektor wyświetli błąd z prośbą o poprawne wprowadzenie informacji.

Poniżej znajduje się karta składająca się z 3 rodzajów widżetów DateTimePicker:

Umożliwianie użytkownikom wybierania elementów

SelectionInputWidżet udostępnia zestaw elementów do wyboru, takich jak pola wyboru, przyciski opcji, przełączniki lub menu. Za pomocą tego widżetu możesz zbierać od użytkowników zdefiniowane i znormalizowane dane. Aby zbierać od użytkowników niezdefiniowane dane, użyj widżetu TextInput.

Widżet SelectionInput obsługuje sugestie, które pomagają użytkownikom wprowadzać jednolite dane, oraz działania po zmianie, które są Actions uruchamiane, gdy w polu do wprowadzania danych wyboru nastąpi zmiana, np. gdy użytkownik wybierze lub odznaczy element.

Aplikacje do obsługi czatu mogą odbierać i przetwarzać wartość wybranych produktów. Więcej informacji o pracy z danymi wejściowymi formularza znajdziesz w artykule Przetwarzanie informacji wprowadzonych przez użytkowników.

Ta sekcja zawiera przykłady kart, które korzystają z widżetu SelectionInput. W przykładach użyto różnych typów danych wejściowych sekcji:

Dodawanie pola wyboru

Poniżej znajduje się karta, na której użytkownik jest proszony o określenie, czy kontakt jest służbowy, osobisty czy oba, z widżetem SelectionInput, który używa pól wyboru:

Dodawanie opcji

Poniżej znajduje się karta z prośbą o określenie, czy kontakt jest służbowy czy osobisty. Zawiera ona widżet SelectionInput z przyciskami opcji:

Dodawanie przełącznika

Poniżej znajduje się karta, która prosi użytkownika o określenie, czy kontakt jest służbowy, osobisty czy oba, za pomocą widżetu SelectionInput, który używa przełączników:

Poniżej znajduje się karta, która prosi użytkownika o określenie, czy kontakt jest służbowy czy prywatny, i zawiera widżet SelectionInput z menu.

Dynamiczne wypełnianie menu

Dostępne w przypadku aplikacji Google Chat.

Możesz dynamicznie wypełniać elementy menu rozwijanego danymi ze źródeł danych w Google Workspace lub z zewnętrznego źródła danych. Aby używać dynamicznych źródeł danych, musisz określić pole data_source_configs, które jest tablicą obiektów DataSourceConfig. Każdy element DataSourceConfig może zawierać element platformDataSource lub remoteDataSource. Obecnie obsługiwany jest tylko 1 element DataSourceConfig.

Wypełnianie elementów z Google Workspace

Aby wypełnić elementy ze źródeł danych Google Workspace, takich jak użytkownicy Google Workspace, określ pole platformDataSource w ramach DataSourceConfig. W przeciwieństwie do statycznych items nie uwzględniasz obiektów SelectionItem, ponieważ te elementy wyboru są dynamicznie pobierane z Google Workspace.

Poniższy kod pokazuje menu, które wypełnia użytkowników Google Workspace:

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "widgets": [
        {
          "selectionInput": {
            "name": "contacts",
            "type": "DROPDOWN",
            "label": "Select contact from organization",
            "data_source_configs": [
              {
                "platformDataSource": {
                  "commonDataSource": "USER"
                },
                "min_characters_trigger": 1
              }
            ]
          }
        }
      ]
    }
  ]
}
Wypełnianie elementów danymi z zewnętrznego źródła danych

Aby wypełnić elementy z zewnętrznego źródła danych, np. systemu zarządzania relacjami z klientami (CRM), użyj pola remoteDataSource w ramach DataSourceConfig, aby określić funkcję, która zwraca elementy ze źródła danych.

Poniższy kod pokazuje menu, które wypełnia elementy z zewnętrznego zestawu kontaktów, uruchamiając funkcję getCrmLeads:

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "widgets": [
        {
          "selectionInput": {
            "name": "crm_leads",
            "type": "DROPDOWN",
            "label": "Select CRM Lead",
            "data_source_configs": [
              {
                "remoteDataSource": {
                  "function": "getCrmLeads"
                },
                "min_characters_trigger": 2
              }
            ],
            "items": [
              {
                "text": "Suggested Lead 1",
                "value": "lead-1"
              }
            ]
          }
        }
      ]
    }
  ]
}

Aby zmniejszyć liczbę żądań wysyłanych do dynamicznego źródła danych, możesz uwzględnić sugerowane elementy, które pojawiają się w menu przed wpisaniem tekstu przez użytkowników. Możesz też skonfigurować menu, aby automatycznie uzupełniało elementy na podstawie tego, co wpisują użytkownicy, ustawiając min_characters_trigger w DataSourceConfig. Gdy użytkownik wpisze co najmniej liczbę znaków określoną w parametrze min_characters_trigger, wywoływana jest funkcja określona w parametrze remoteDataSource. Obiekt zdarzenia przekazywany do funkcji zawiera dane wejściowe użytkownika w kluczu autocomplete_widget_query.

Dodawanie menu wielokrotnego wyboru

Poniższy kod wyświetla kartę z prośbą o wybranie kontaktów z menu wielokrotnego wyboru:

Elementy menu wielokrotnego wyboru możesz wypełniać danymi z tych źródeł w Google Workspace:

  • Użytkownicy Google Workspace: możesz wypełnić listę tylko użytkownikami z tej samej organizacji Google Workspace.
  • Pokoje czatu: użytkownik wpisujący elementy w menu wielokrotnego wyboru może wyświetlać i wybierać tylko pokoje, do których należy w organizacji Google Workspace.

Aby używać źródeł danych Google Workspace, musisz określić pole platformDataSource. W przeciwieństwie do innych typów danych wejściowych wyboru pomijasz obiekty SelectionItem, ponieważ te elementy wyboru są dynamicznie pobierane z Google Workspace.

Poniższy kod przedstawia menu wielokrotnego wyboru użytkowników Google Workspace. Aby wypełnić listę użytkowników, w polu wyboru ustaw wartość commonDataSource na USER:

JSON

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

Poniższy kod pokazuje menu wielokrotnego wyboru przestrzeni na czacie. Aby wypełnić miejsca, w polu wyboru należy podać pole hostAppDataSource. W menu wielokrotnego wyboru ustawia się też wartość defaultToCurrentSpace na true, co sprawia, że bieżący pokój jest domyślnie wybierany w menu:

JSON

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

Menu wielokrotnego wyboru mogą też zawierać elementy pochodzące ze źródła danych zewnętrznego lub firmy zewnętrznej. Możesz na przykład użyć menu wielokrotnego wyboru, aby pomóc użytkownikowi wybrać z listy potencjalnych klientów z systemu zarządzania relacjami z klientami (CRM).

Aby użyć zewnętrznego źródła danych, w polu externalDataSource musisz podać funkcję, która zwraca elementy ze źródła danych.

Aby zmniejszyć liczbę żądań wysyłanych do zewnętrznego źródła danych, możesz uwzględnić sugerowane elementy, które pojawiają się w menu wielokrotnego wyboru, zanim użytkownicy wpiszą tekst w menu. Możesz na przykład wypełnić listę ostatnio wyszukiwanych kontaktów użytkownika. Aby wypełnić sugerowane produkty z zewnętrznego źródła danych, określ SelectionItem obiekty.

Poniższy przykładowy kod pokazuje menu wielokrotnego wyboru, które wysyła zapytania i wypełnia elementy z zewnętrznego źródła danych:

Node.js

node/chat/selection-input/index.js
selectionInput: {
  name: "contacts",
  type: "MULTI_SELECT",
  label: "Selected contacts",
  multiSelectMaxSelectedItems: 3,
  multiSelectMinQueryLength: 1,
  externalDataSource: { function: FUNCTION_URL },
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  items: [getSuggestedContact("3")]
}

Zastąp FUNCTION_URL punktem końcowym HTTP, który wysyła zapytania do zewnętrznego źródła danych.

Python

python/chat/selection-input/main.py
'selectionInput': {
  'name': "contacts",
  'type': "MULTI_SELECT",
  'label': "Selected contacts",
  'multiSelectMaxSelectedItems': 3,
  'multiSelectMinQueryLength': 1,
  'externalDataSource': { 'function': FUNCTION_URL },
  # Suggested items loaded by default.
  # The list is static here but it could be dynamic.
  'items': [get_suggested_contact("3")]
}

Zastąp FUNCTION_URL punktem końcowym HTTP, który wysyła zapytania do zewnętrznego źródła danych.

Java

java/chat/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(FUNCTION_URL))
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  .setItems(List.of(getSuggestedContact("3")))))))))));

Zastąp FUNCTION_URL punktem końcowym HTTP, który wysyła zapytania do zewnętrznego źródła danych.

Google Apps Script

W tym przykładzie wysyłana jest wiadomość z kartą przez zwrócenie kodu JSON karty. Możesz też użyć usługi kart Apps Script.

apps-script/chat/selection-input/selection-input.gs
selectionInput: {
  name: "contacts",
  type: "MULTI_SELECT",
  label: "Selected contacts",
  multiSelectMaxSelectedItems: 3,
  multiSelectMinQueryLength: 1,
  externalDataSource: { function: "queryContacts" },
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  items: [getSuggestedContact("3")]
}

Wypełnianie sugerowanych produktów danymi z dynamicznego źródła danych

W przypadku zewnętrznych źródeł danych możesz też autouzupełniać i sugerować elementy, które użytkownicy zaczynają wpisywać w menu wielokrotnego wyboru lub menu. Jeśli na przykład użytkownik zacznie wpisywać Atl w menu, które zawiera miasta w Stanach Zjednoczonych, aplikacja Google Chat może automatycznie zasugerować Atlanta, zanim użytkownik skończy pisać. Możesz zaproponować maksymalnie 100 produktów.

Aby zwrócić sugerowane produkty, funkcja, która wysyła zapytanie do zewnętrznego źródła danych, musi wykonać te czynności:

  1. Obsłuż obiekt zdarzenia, który aplikacja do obsługi czatu otrzymuje, gdy użytkownicy wpisują tekst w menu.
  2. Z obiektu zdarzenia pobierz wartość wpisaną przez użytkownika, która jest reprezentowana w polu event.commonEventObject.parameters["autocomplete_widget_query"].
  3. Wysyłaj do źródła danych zapytania z danymi wejściowymi użytkownika, aby uzyskać co najmniej 1 SelectionItems do zaproponowania użytkownikowi.
  4. Zwróć sugerowane produkty, zwracając działanieRenderActions z obiektem modifyCard.

Poniższy przykładowy kod pokazuje, jak aplikacja w Google Chat dynamicznie sugeruje elementy w menu wielokrotnego wyboru na karcie. Gdy użytkownik wpisuje tekst w menu, funkcja lub punkt końcowy podany w polu externalDataSource widżetu wysyła zapytanie do zewnętrznego źródła danych i sugeruje elementy, które użytkownik może wybrać:

Node.js

node/chat/selection-input/index.js
/**
 * Web app that responds to events sent from a Google Chat space.
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
app.post('/', async (req, res) => {
  // Stores the Google Chat event
  const chatEvent = req.body.chat;

  // Handle user interaction with multiselect.
  if(chatEvent.widgetUpdatedPayload) {
    return res.json(queryContacts(req.body));
  }

  // Replies with a card that contains the multiselect menu.
  return res.json({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    cardsV2: [{
      cardId: "contactSelector",
      card: { sections:[{ widgets: [{
        selectionInput: {
          name: "contacts",
          type: "MULTI_SELECT",
          label: "Selected contacts",
          multiSelectMaxSelectedItems: 3,
          multiSelectMinQueryLength: 1,
          externalDataSource: { function: FUNCTION_URL },
          // Suggested items loaded by default.
          // The list is static here but it could be dynamic.
          items: [getSuggestedContact("3")]
        }
      }]}]}
    }]
  }}}}});
});

/**
 * Get contact suggestions based on text typed by users.
 *
 * @param {Object} event the event object that contains the user's query
 * @return {Object} suggestions
 */
function queryContacts(event) {
  const query = event.commonEventObject.parameters["autocomplete_widget_query"];
  return { action: { modifyOperations: [{ updateWidget: { selectionInputWidgetSuggestions: { suggestions: [
    // The list is static here but it could be dynamic.
    getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("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 selection item in the menu.
 */
function getSuggestedContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}

Zastąp FUNCTION_URL punktem końcowym HTTP, który wysyła zapytania do zewnętrznego źródła danych.

Python

python/chat/selection-input/main.py
@app.route('/', methods=['POST'])
def post() -> Mapping[str, Any]:
  """Handle requests from Google Chat

  Returns:
      Mapping[str, Any]: The response
  """
  # Stores the Google Chat event
  chatEvent = request.get_json().get('chat')

  # Handle user interaction with multiselect.
  if chatEvent.get('widgetUpdatedPayload') is not None:
    return json.jsonify(query_contacts(request.get_json()))

  # Replies with a card that contains the multiselect menu.
  return json.jsonify({ 'hostAppDataAction': { 'chatDataAction': { 'createMessageAction': {
    'message': { 'cardsV2': [{
      'cardId': "contactSelector",
      'card': { 'sections':[{ 'widgets': [{
        'selectionInput': {
          'name': "contacts",
          'type': "MULTI_SELECT",
          'label': "Selected contacts",
          'multiSelectMaxSelectedItems': 3,
          'multiSelectMinQueryLength': 1,
          'externalDataSource': { 'function': FUNCTION_URL },
          # Suggested items loaded by default.
          # The list is static here but it could be dynamic.
          'items': [get_suggested_contact("3")]
        }
      }]}]}
    }]}
  }}}})


def query_contacts(event: dict) -> dict:
  """Get contact suggestions based on text typed by users.

  Args:
      event (Mapping[str, Any]): The event object that contains the user's query

  Returns:
      Mapping[str, Any]: The response with contact suggestions.
  """
  query = event.get("commonEventObject").get("parameters").get("autocomplete_widget_query")
  return { 'action': { 'modifyOperations': [{ 'updateWidget': { 'selectionInputWidgetSuggestions': { 'suggestions': list(
    filter(lambda e: query is None or query in e["text"], [
      # The list is static here but it could be dynamic.
      get_suggested_contact("1"), get_suggested_contact("2"), get_suggested_contact("3"), get_suggested_contact("4"), get_suggested_contact("5")
    # Only return items based on the query from the user
    ])
  )}}}]}}


def get_suggested_contact(id: str) -> dict:
  """Generate a suggested contact given an ID.

  Args:
      id (str): The ID of the contact to return.

  Returns:
      Mapping[str, Any]: The contact formatted as a selection item in the menu.
  """
  return {
    'value': id,
    'startIconUri': "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    'text': "Contact " + id
  }

Zastąp FUNCTION_URL punktem końcowym HTTP, który wysyła zapytania do zewnętrznego źródła danych.

Java

java/chat/selection-input/src/main/java/com/google/chat/selectionInput/App.java
@SpringBootApplication
@RestController
// Web app that responds to events sent from a Google Chat space.
public class App {
  private static final String FUNCTION_URL = "your-function-url";

  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }

  /**
   * Handle requests from Google Chat
   * 
   * @param event the event object sent by Google Chat
   * @return The response to be sent back to Google Chat
   */
  @PostMapping("/")
  @ResponseBody
  public GenericJson onEvent(@RequestBody JsonNode event) throws Exception {
    // Stores the Google Chat event
    JsonNode chatEvent = event.at("/chat");

    // Handle user interaction with multiselect.
    if (!chatEvent.at("/widgetUpdatedPayload").isEmpty()) {
      return queryContacts(event);
    }

    // Replies with a card that contains the multiselect menu.
    Message message = new Message().setCardsV2(List.of(new CardWithId()
      .setCardId("contactSelector")
      .setCard(new GoogleAppsCardV1Card()
        .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(new GoogleAppsCardV1Widget()
          .setSelectionInput(new GoogleAppsCardV1SelectionInput()
            .setName("contacts")
            .setType("MULTI_SELECT")
            .setLabel("Selected contacts")
            .setMultiSelectMaxSelectedItems(3)
            .setMultiSelectMinQueryLength(1)
            .setExternalDataSource(new GoogleAppsCardV1Action().setFunction(FUNCTION_URL))
            // Suggested items loaded by default.
            // The list is static here but it could be dynamic.
            .setItems(List.of(getSuggestedContact("3")))))))))));

    return new GenericJson() {{
      put("hostAppDataAction", new GenericJson() {{
        put("chatDataAction", new GenericJson() {{
          put("createMessageAction", new GenericJson() {{
            put("message", message);
          }});
        }});
      }});
    }};
  }

  /**
   * Get contact suggestions based on text typed by users.
   *
   * @param event the event object that contains the user's query.
   * @return The response with contact suggestions.
   */
  GenericJson queryContacts(JsonNode event) throws Exception {
    String query = event.at("/commonEventObject/parameters/autocomplete_widget_query").asText();
    List<GoogleAppsCardV1SelectionItem> suggestions = List.of(
      // The list is static here but it could be dynamic.
      getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("5")
    // Only return items based on the query from the user
    ).stream().filter(e -> query == null || e.getText().indexOf(query) > -1).toList();

    return new GenericJson() {{
      put("action", new GenericJson() {{
        put("modifyOperations", List.of(new GenericJson() {{
          put("updateWidget", new GenericJson() {{
            put("selectionInputWidgetSuggestions", new GenericJson() {{
              put("suggestions", suggestions);
            }});
          }});
        }}));
      }});
    }};
  }

  /**
   * Generate a suggested contact given an ID.
   * 
   * @param id The ID of the contact to return.
   * @return The contact formatted as a selection item in the menu.
   */
  GoogleAppsCardV1SelectionItem getSuggestedContact(String id) {
    return new GoogleAppsCardV1SelectionItem()
      .setValue(id)
      .setStartIconUri("https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png")
      .setText("Contact " + id);
  }
}

Zastąp FUNCTION_URL punktem końcowym HTTP, który wysyła zapytania do zewnętrznego źródła danych.

Google Apps Script

W tym przykładzie wysyłana jest wiadomość z kartą przez zwrócenie kodu JSON karty. Możesz też użyć usługi kart Apps Script.

apps-script/chat/selection-input/selection-input.gs
/**
* Responds to a Message trigger in Google Chat.
*
* @param {Object} event the event object from Google Chat
* @return {Object} Response from the Chat app.
*/
function onMessage(event) {
  // Replies with a card that contains the multiselect menu.
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    cardsV2: [{
      cardId: "contactSelector",
      card: { sections:[{ widgets: [{
        selectionInput: {
          name: "contacts",
          type: "MULTI_SELECT",
          label: "Selected contacts",
          multiSelectMaxSelectedItems: 3,
          multiSelectMinQueryLength: 1,
          externalDataSource: { function: "queryContacts" },
          // Suggested items loaded by default.
          // The list is static here but it could be dynamic.
          items: [getSuggestedContact("3")]
        }
      }]}]}
    }]
  }}}}};
}

/**
* Get contact suggestions based on text typed by users.
*
* @param {Object} event the event object that contains the user's query
* @return {Object} suggestions
*/
function queryContacts(event) {
  const query = event.commonEventObject.parameters["autocomplete_widget_query"];
  return { action: { modifyOperations: [{ updateWidget: { selectionInputWidgetSuggestions: { suggestions: [
    // The list is static here but it could be dynamic.
    getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("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 selection item in the menu.
*/
function getSuggestedContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}

Sprawdzanie danych wprowadzonych na kartach

Na tej stronie dowiesz się, jak weryfikować dane wprowadzane na karcie action i w widżetach. Możesz na przykład sprawdzić, czy w polu do wprowadzania danych użytkownik wpisał tekst lub czy zawiera ono określoną liczbę znaków.

Ustawianie wymaganych widżetów dla działań

W ramach action karty dodaj nazwy widżetów, których działanie potrzebuje, do listy requiredWidgets.

Jeśli w momencie wywołania tego działania którykolwiek z wymienionych tu widżetów nie ma wartości, przesyłanie działania formularza zostanie anulowane.

Jeśli dla działania ustawiono wartość "all_widgets_are_required": "true", wszystkie widżety na karcie są wymagane przez to działanie.

Ustawianie działania all_widgets_are_required w przypadku wielokrotnego wyboru

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
              }
            ]
          }
        }
      ]
    }
  ]
}
Ustawianie działania all_widgets_are_required w selektorze daty i godziny

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"
          }
        }
      ]
    }
  ]
}
Ustaw all_widgets_are_required działanie w menu

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

Ustawianie sprawdzania poprawności w przypadku widżetu wprowadzania tekstu

W polu weryfikacji widżetu textInput można określić limit znaków i typ danych wejściowych dla tego widżetu wprowadzania tekstu.

Ustawianie limitu znaków w widżecie wprowadzania tekstu

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
            }
          }
        }
      ]
    }
  ]
}
Ustawianie typu danych wejściowych w widżecie wprowadzania tekstu

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

Rozwiązywanie problemów

Gdy aplikacja Google Chat lub karta zwróci błąd, w interfejsie Google Chat pojawi się komunikat „Coś poszło nie tak”. lub „Nie udało się przetworzyć żądania”. Czasami interfejs Google Chat nie wyświetla żadnego komunikatu o błędzie, ale aplikacja lub karta Google Chat zwraca nieoczekiwany wynik, np. może nie pojawić się wiadomość na karcie.

Chociaż w interfejsie czatu może nie wyświetlać się komunikat o błędzie, opisowe komunikaty o błędach i dane logowania są dostępne, aby pomóc w naprawieniu błędów, gdy rejestrowanie błędów w aplikacjach na czat jest włączone. Pomoc dotyczącą wyświetlania, debugowania i naprawiania błędów znajdziesz w artykule Rozwiązywanie problemów z Google Chat.

Aplikacje do obsługi czatu, które nie są dodatkami: projektowanie interaktywnych kart i okien

Poniższa dokumentacja dotyczy aplikacji do Google Chat, które nie są dodatkami do Google Workspace. Aby przeprowadzić migrację aplikacji do czatu, która nie jest dodatkiem, przeczytaj artykuł Przekształcanie aplikacji do Google Chat w dodatek do Google Workspace.

Poniższy kod pokazuje menu wielokrotnego wyboru elementów z zewnętrznego zestawu kontaktów użytkownika w aplikacji do obsługi czatu, która nie jest dodatkiem. Menu domyślnie wyświetla 1 kontakt i uruchamia funkcję getContacts, aby pobrać i wypełnić elementy ze zewnętrznego źródła danych:

Node.js

node/selection-input/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

python/selection-input/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

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")))))))))));

Google Apps Script

apps-script/selection-input/selection-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")]
}

Aby autouzupełniać elementy w aplikacji Google Chat, która nie jest dodatkiem, utwórz funkcję, która wysyła zapytanie do zewnętrznego źródła danych i zwraca elementy, gdy użytkownik wpisuje tekst w menu wielokrotnego wyboru. Funkcja musi wykonywać te czynności:

  • Przekaż obiekt zdarzenia, który reprezentuje interakcję użytkownika z menu.
  • Sprawdź, czy wartość zdarzenia interakcji invokedFunction jest zgodna z funkcją z pola externalDataSource.
  • Jeśli funkcje są zgodne, zwracaj sugerowane produkty ze źródła danych zewnętrznych. Aby sugerować produkty na podstawie tego, co wpisuje użytkownik, pobierz wartość klucza autocomplete_widget_query. Ta wartość reprezentuje to, co użytkownik wpisuje w menu.

Poniższy kod automatycznie uzupełnia elementy z zewnętrznego źródła danych. W poprzednim przykładzie aplikacja do Google Chat, która nie jest dodatkiem, sugeruje elementy na podstawie tego, kiedy zostanie wywołana funkcja getContacts:

Node.js

node/selection-input/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

python/selection-input/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

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

Google Apps Script

apps-script/selection-input/selection-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
  };
}