Collecter et traiter les informations des utilisateurs de Google Chat

Ce guide explique comment les applications Google Chat peuvent collecter et traiter les informations des utilisateurs en créant des entrées de formulaire dans des interfaces basées sur des cartes.

Boîte de dialogue comportant différents widgets.
Figure 1 : Exemple d'application Chat qui ouvre une boîte de dialogue pour collecter des coordonnées.

Les applications Chat demandent des informations aux utilisateurs pour effectuer des actions dans ou en dehors de Chat, y compris de la manière suivante :

  • Configurez les paramètres. Par exemple, pour permettre aux utilisateurs de personnaliser les paramètres de notification ou de configurer et d'ajouter l'application Chat à un ou plusieurs espaces.
  • Créer ou mettre à jour des informations dans d'autres applications Google Workspace Par exemple, autorisez les utilisateurs à créer un événement Google Agenda.
  • Permettez aux utilisateurs d'accéder à des ressources dans d'autres applications ou services Web, et de les mettre à jour. Par exemple, une application Chat peut aider les utilisateurs à mettre à jour l'état d'une demande d'assistance directement depuis un espace Chat.

Prérequis

HTTP

Une application Google Chat qui reçoit des interactions utilisateur et y répond. Pour en créer un, suivez le guide de démarrage rapide HTTP.

Apps Script

Une application Google Chat qui reçoit des interactions utilisateur et y répond. Pour en créer un, suivez le guide de démarrage rapide d'Apps Script.

Créer des formulaires à l'aide de fiches

Pour collecter des informations, les applications Chat conçoivent des formulaires et leurs entrées, et les intègrent dans des fiches. Pour afficher des fiches aux utilisateurs, les applications Chat peuvent utiliser les interfaces Chat suivantes :

  • Messages contenant une ou plusieurs fiches.
  • Pages d'accueil, qui sont des fiches qui s'affichent dans l'onglet Accueil des messages privés avec l'application Chat.
  • Boîtes de dialogue, qui sont des fiches s'ouvrant dans une nouvelle fenêtre à partir de messages et de pages d'accueil.

Les applications Chat peuvent créer les fiches à l'aide des widgets suivants :

  • Widgets de saisie de formulaire qui demandent des informations aux utilisateurs. Vous pouvez éventuellement ajouter une validation aux widgets de saisie de formulaire pour vous assurer que les utilisateurs saisissent et mettent en forme les informations correctement. Les applications Chat peuvent utiliser les widgets de saisie de formulaire suivants :

  • Un widget bouton pour que les utilisateurs puissent envoyer les valeurs qu'ils ont saisies dans la fiche. Une fois que l'utilisateur a cliqué sur le bouton, l'application Chat peut traiter les informations qu'elle reçoit.

Dans l'exemple suivant, une fiche collecte des coordonnées à l'aide d'une saisie de texte, d'un sélecteur de date et d'heure, et d'une saisie de sélection :

Pour obtenir d'autres exemples de widgets interactifs que vous pouvez utiliser pour collecter des informations, consultez Concevoir une fiche ou une boîte de dialogue interactive.

Ajouter un menu déroulant

Pour personnaliser les éléments de sélection ou permettre aux utilisateurs de sélectionner un seul élément d'une source de données dynamique, les applications Chat peuvent utiliser des menus déroulants, qui sont un type de widget SelectionInput. Par exemple, la fiche suivante affiche un menu déroulant dans lequel les utilisateurs peuvent sélectionner dynamiquement un contact dans une liste :

Vous pouvez renseigner les éléments d'un menu déroulant à partir des sources de données suivantes :

Remplir des éléments à partir d'une source de données Google Workspace

Pour renseigner des éléments à partir de sources de données Google Workspace, telles que des utilisateurs Google Workspace, spécifiez le champ platformDataSource dans un objet DataSourceConfig. Contrairement aux autres types d'entrées de sélection, vous omettez les objets SelectionItem, car ces éléments de sélection proviennent de manière dynamique de Google Workspace.

Le code suivant affiche un menu déroulant des utilisateurs Google Workspace :

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "widgets": [
        {
          "selectionInput": {
            "name": "contacts",
            "type": "DROPDOWN",
            "label": "Select contact from organization",
            "dataSourceConfigs": [
              {
                "platformDataSource": {
                  "commonDataSource": "USER"
                },
                "minCharactersTrigger": 1
              }
            ]
          }
        }
      ]
    }
  ]
}

Remplir des éléments à partir d'une source de données externe

Les menus déroulants peuvent également renseigner des éléments à partir d'une source de données tierce ou externe. Pour utiliser une source de données externe, vous devez spécifier le champ remoteDataSource dans un objet DataSourceConfig contenant la fonction qui interroge et renvoie les éléments de la source de données.

Pour réduire les requêtes adressées à une source de données externe, vous pouvez inclure des éléments suggérés qui s'affichent dans le menu déroulant avant que les utilisateurs ne saisissent du texte dans le menu. Pour renseigner les éléments suggérés à partir d'une source de données externe, spécifiez des objets SelectionItem statiques.

Le code suivant montre un menu déroulant qui interroge et remplit des éléments à partir d'une source de données externe :

JSON

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

Pour obtenir un exemple complet illustrant comment renvoyer des éléments suggérés, consultez la section Suggérer des éléments de sélection.

Ajouter un menu de sélection multiple

Pour personnaliser les éléments de sélection ou permettre aux utilisateurs de sélectionner des éléments à partir d'une source de données dynamique, les applications Chat peuvent utiliser des menus à sélection multiple, qui sont un type de widget SelectionInput. Par exemple, la fiche suivante affiche un menu à sélection multiple dans lequel les utilisateurs peuvent sélectionner dynamiquement des contacts dans une liste :

Vous pouvez renseigner les éléments d'un menu à sélection multiple à partir des sources de données suivantes :

  • Données Google Workspace, qui incluent les utilisateurs ou les espaces Chat dont l'utilisateur est membre. Le menu ne contient que les éléments de la même organisation Google Workspace.
  • Sources de données externes, telles qu'une base de données relationnelle. Par exemple, vous pouvez utiliser des menus à sélection multiple pour aider un utilisateur à sélectionner des éléments dans une liste de leads commerciaux d'un système de gestion de la relation client (CRM).

Remplir des éléments à partir d'une source de données Google Workspace

Pour utiliser des sources de données Google Workspace, spécifiez le champ platformDataSource dans le widget SelectionInput. Contrairement aux autres types d'entrées de sélection, vous omettez les objets SelectionItem, car ces éléments de sélection proviennent de manière dynamique de Google Workspace.

Le code suivant montre un menu à sélection multiple d'utilisateurs Google Workspace. Pour renseigner les utilisateurs, l'entrée de sélection définit commonDataSource sur USER :

JSON

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

Le code suivant montre un menu de sélection multiple d'espaces Chat. Pour renseigner les espaces, l'entrée de sélection spécifie le champ hostAppDataSource. Le menu de sélection multiple définit également defaultToCurrentSpace sur true, ce qui fait de l'espace actuel la sélection par défaut dans le menu :

JSON

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

Remplir des éléments à partir d'une source de données externe

Les menus à sélection multiple peuvent également renseigner des éléments à partir d'une source de données tierce ou externe. Pour utiliser une source de données externe, vous devez spécifier le champ externalDataSource dans le widget SelectionInput qui contient la fonction qui interroge et renvoie les éléments de la source de données.

Pour réduire les requêtes adressées à une source de données externe, vous pouvez inclure des éléments suggérés qui s'affichent dans le menu de sélection multiple avant que les utilisateurs ne saisissent du texte dans le menu. Par exemple, vous pouvez renseigner les contacts récemment recherchés pour l'utilisateur. Pour renseigner les éléments suggérés à partir d'une source de données externe, spécifiez des objets SelectionItem statiques.

L'exemple de code suivant montre un menu à sélection multiple qui interroge et renseigne des éléments à partir d'une source de données externe :

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

Remplacez FUNCTION_URL par le point de terminaison HTTP qui interroge la source de données externe.

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

Remplacez FUNCTION_URL par le point de terminaison HTTP qui interroge la source de données externe.

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

Remplacez FUNCTION_URL par le point de terminaison HTTP qui interroge la source de données externe.

Apps Script

Cet exemple envoie un message de fiche en renvoyant un fichier JSON de fiche. Vous pouvez également utiliser le service de fiches 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")]
}

Pour obtenir un exemple complet illustrant comment renvoyer des éléments suggérés, consultez la section Suggérer des éléments de sélection.

Recevoir des données de widgets interactifs

Chaque fois qu'un utilisateur clique sur un bouton, l'action de l'application Chat est déclenchée avec des informations sur l'interaction. Dans le champ commonEventObject de la charge utile de l'événement, l'objet formInputs contient toutes les valeurs saisies par l'utilisateur.

Vous pouvez récupérer les valeurs de l'objet event.commonEventObject.formInputs.WIDGET_NAME, où WIDGET_NAME est le champ name que vous avez spécifié pour le widget. Les valeurs sont renvoyées sous la forme d'un type de données spécifique pour le widget.

L'exemple suivant montre une partie d'un objet d'événement dans lequel un utilisateur a saisi des valeurs pour chaque widget :

{
  "commonEventObject": { "formInputs": {
    "contactName": { "stringInputs": {
      "value": ["Kai 0"]
    }},
    "contactBirthdate": { "dateInput": {
      "msSinceEpoch": 1000425600000
    }},
    "contactType": { "stringInputs": {
      "value": ["Personal"]
    }}
  }}
}

Pour recevoir les données, votre application Chat gère l'objet d'événement afin d'obtenir les valeurs saisies par les utilisateurs dans les widgets. Le tableau suivant montre comment obtenir la valeur d'un widget de saisie de formulaire donné. Pour chaque widget, le tableau indique le type de données qu'il accepte, l'emplacement de stockage de la valeur dans l'objet d'événement et un exemple de valeur.

Widget de saisie de formulaire Type de données d'entrée Valeur d'entrée de l'objet d'événement Exemple de valeur
textInput stringInputs event.commonEventObject.formInputs.contactName.stringInputs.value[0] Kai O
selectionInput stringInputs Pour obtenir la première ou l'unique valeur, event.commonEventObject.formInputs.contactType.stringInputs.value[0] Personal
dateTimePicker qui n'accepte que les dates. dateInput event.commonEventObject.formInputs.contactBirthdate.dateInput.msSinceEpoch. 1000425600000

Une fois que l'application Chat a reçu les données, elle peut effectuer l'une des opérations suivantes :

Suggérer des éléments de sélection

Si une fiche contient un menu à sélection multiple ou un menu déroulant qui remplit des éléments à partir d'une source de données externe, l'application Chat peut renvoyer des éléments suggérés en fonction de ce que les utilisateurs saisissent dans le menu. Par exemple, si un utilisateur commence à saisir Atl pour un menu qui affiche des villes des États-Unis, votre application Chat peut suggérer automatiquement Atlanta avant que l'utilisateur ait fini de saisir sa requête. L'application Chat peut suggérer jusqu'à 100 éléments.

Pour suggérer et renseigner de manière dynamique des éléments dans une entrée de sélection, le widget SelectionInput de la fiche doit spécifier une fonction qui interroge la source de données externe. Pour les menus à sélection multiple, vous devez spécifier le champ externalDataSource. Pour les menus déroulants, vous spécifiez le champ remoteDataSource dans un objet DataSourceConfig.

Vous pouvez également configurer le nombre de caractères qu'un utilisateur doit saisir avant que le menu ne renvoie des suggestions. Pour les menus à sélection multiple, définissez le champ multiSelectMinQueryLength. Pour les menus déroulants, définissez le champ min_characters_trigger dans DataSourceConfig.

Pour renvoyer des éléments suggérés, la fonction doit effectuer les opérations suivantes :

  1. Gérer un objet d'événement, que l'application Chat reçoit lorsque les utilisateurs saisissent du texte dans le menu.
  2. À partir de l'objet d'événement, récupérez la valeur saisie par l'utilisateur, qui est représentée dans le champ event.commonEventObject.parameters["autocomplete_widget_query"].
  3. Interrogez la source de données à l'aide de la valeur saisie par l'utilisateur pour obtenir un ou plusieurs SelectionItems à suggérer à l'utilisateur.
  4. Renvoyez les éléments suggérés en renvoyant l'action RenderActions avec un objet modifyCard.

L'exemple de code suivant montre comment une application Chat suggère de manière dynamique des éléments dans le menu de sélection multiple d'une fiche. Lorsqu'un utilisateur saisit du texte dans le menu, la fonction ou le point de terminaison fourni dans le champ externalDataSource du widget interroge une source de données externe et suggère des éléments que l'utilisateur peut sélectionner.

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

Remplacez FUNCTION_URL par le point de terminaison HTTP qui interroge la source de données externe.

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
  }

Remplacez FUNCTION_URL par le point de terminaison HTTP qui interroge la source de données externe.

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

Remplacez FUNCTION_URL par le point de terminaison HTTP qui interroge la source de données externe.

Apps Script

Cet exemple envoie un message de fiche en renvoyant un fichier JSON de fiche. Vous pouvez également utiliser le service de fiches 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
  };
}

Transférer les données vers une autre carte

Une fois qu'un utilisateur a envoyé des informations à partir d'une fiche, vous devrez peut-être renvoyer des fiches supplémentaires pour effectuer l'une des opérations suivantes :

  • Aidez les utilisateurs à remplir des formulaires plus longs en créant des sections distinctes.
  • Permettez aux utilisateurs de prévisualiser et de confirmer les informations de la fiche initiale afin qu'ils puissent vérifier leurs réponses avant de les envoyer.
  • Remplissez de manière dynamique les autres parties du formulaire. Par exemple, pour inviter les utilisateurs à prendre un rendez-vous, une application Chat peut afficher une fiche initiale demandant le motif du rendez-vous, puis remplir une autre fiche indiquant les horaires disponibles en fonction du type de rendez-vous.

Pour transférer la saisie de données de la fiche initiale, vous pouvez créer le widget button avec des actionParameters contenant le name du widget et la valeur saisie par l'utilisateur, comme illustré dans l'exemple suivant :

Node.js

node/chat/contact-form-app/index.js
{ buttonList: { buttons: [{
  text: "SUBMIT",
  onClick: { action: {
    function: FUNCTION_URL,
    parameters: [
      { key: "actionName", value: "submitDialog" },
      // Pass input values as parameters for last dialog step (submission)
      { key: "contactName", value: name },
      { key: "contactBirthdate", value: birthdate },
      { key: "contactType", value: type }
    ]
  }}
}]}}

Remplacez FUNCTION_URL par le point de terminaison HTTP qui gère les clics sur le bouton.

Python

python/chat/contact-form-app/main.py
{ 'buttonList': { 'buttons': [{
  'text': "SUBMIT",
  'onClick': { 'action': {
    'function': FUNCTION_URL,
    'parameters': [
      { 'key': "actionName", 'value': "submitDialog" },
      # Pass input values as parameters for last dialog step (submission)
      { 'key': "contactName", 'value': name },
      { 'key': "contactBirthdate", 'value': birthdate },
      { 'key': "contactType", 'value': type }
    ]
  }}
}]}}

Remplacez FUNCTION_URL par le point de terminaison HTTP qui gère les clics sur le bouton.

Java

java/chat/contact-form-app/src/main/java/com/google/chat/contact/App.java
new GoogleAppsCardV1Widget().setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(
  new GoogleAppsCardV1Button()
    .setText("SUBMIT")
    .setOnClick(new GoogleAppsCardV1OnClick().setAction(new GoogleAppsCardV1Action()
      .setFunction(FUNCTION_URL)
      .setParameters(List.of(
        new GoogleAppsCardV1ActionParameter().setKey("actionName").setValue("submitDialog"),
        // Pass input values as parameters for last dialog step (submission)
        new GoogleAppsCardV1ActionParameter().setKey("contactName").setValue(name),
        new GoogleAppsCardV1ActionParameter().setKey("contactBirthdate").setValue(birthdate),
        new GoogleAppsCardV1ActionParameter().setKey("contactType").setValue(type))))))))))));

Remplacez FUNCTION_URL par le point de terminaison HTTP qui gère les clics sur le bouton.

Apps Script

Cet exemple envoie un message de fiche en renvoyant un fichier JSON de fiche. Vous pouvez également utiliser le service de fiches Apps Script.

apps-script/chat/contact-form-app/Code.gs
{ buttonList: { buttons: [{
  text: "SUBMIT",
  onClick: { action: {
    function: "submitDialog",
    // Pass input values as parameters for last dialog step (submission)
    parameters: [
      { key: "contactName", value: name },
      { key: "contactBirthdate", value: birthdate },
      { key: "contactType", value: type }
    ]
  }}
}]}}

Lorsqu'un utilisateur clique sur le bouton, votre application Chat reçoit un objet d'événement à partir duquel vous pouvez recevoir des données.

Répondre à l'envoi d'un formulaire

Après avoir reçu les données d'un message de fiche ou d'une boîte de dialogue, l'application Chat répond en accusant réception ou en renvoyant une erreur.

Dans l'exemple suivant, une application Chat envoie un message pour confirmer qu'elle a bien reçu un formulaire envoyé à partir d'un message de fiche.

Node.js

node/chat/contact-form-app/index.js
return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
  text: "✅ " + event.commonEventObject.parameters["contactName"] + " has been added to your contacts."
}}}}};

Python

python/chat/contact-form-app/main.py
return { 'hostAppDataAction': { 'chatDataAction': { 'createMessageAction': { 'message': {
  'text': "✅ " + event.get('commonEventObject').get('parameters')["contactName"] + " has been added to your contacts."
}}}}}

Java

java/chat/contact-form-app/src/main/java/com/google/chat/contact/App.java
return new GenericJson() {{
  put("hostAppDataAction", new GenericJson() {{
    put("chatDataAction", new GenericJson() {{
      put("createMessageAction", new GenericJson() {{
        put("message", new Message()
          .setText( "✅ " + event.at("/commonEventObject/parameters/contactName").asText() +
                    " has been added to your contacts."));
      }});
    }});
  }});
}};

Apps Script

Cet exemple envoie un message de fiche en renvoyant un fichier JSON de fiche. Vous pouvez également utiliser le service de fiches Apps Script.

apps-script/chat/contact-form-app/Code.gs
return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
  text: "✅ " + event.commonEventObject.parameters["contactName"] + " has been added to your contacts."
}}}}};

Pour traiter et fermer une boîte de dialogue, vous devez renvoyer un objet RenderActions qui indique si vous souhaitez envoyer un message de confirmation, mettre à jour le message ou la fiche d'origine, ou simplement fermer la boîte de dialogue. Pour connaître la procédure à suivre, consultez Fermer une boîte de dialogue.

Résoudre les problèmes

Cette section fournit des étapes de dépannage pour des codes d'erreur et des comportements d'exécution spécifiques lors de l'interaction avec des boîtes de dialogue dans Chat.

Les interactions avec la boîte de dialogue renvoient l'erreur "Erreur non spécifiée lors de l'appel du module complémentaire"

Lorsque vous interagissez avec une boîte de dialogue, si vous voyez des journaux d'erreurs avec le message "Erreur non spécifiée lors de l'appel du module complémentaire" et le code 13, cela indique généralement une erreur interne ou que le point de terminaison HTTP de l'application Chat n'a pas pu traiter la requête ou renvoyer une réponse valide.

Pour résoudre cette erreur :

  • Vérifiez les journaux de votre point de terminaison HTTP pour détecter d'éventuelles exceptions non gérées ou des plantages.
  • Vérifiez que votre point de terminaison répond aux requêtes dans un délai de 30 secondes. Si l'exécution du point de terminaison prend plus de 30 secondes, Chat ne peut pas traiter la réponse et l'interaction échoue. Pour en savoir plus, consultez Limites de débit et bonnes pratiques.
  • Assurez-vous que votre point de terminaison renvoie une réponse valide. Pour les envois de boîtes de dialogue, le point de terminaison doit renvoyer un objet RenderActions au format JSON correct. Si la réponse est incorrecte ou ne contient pas les champs obligatoires, l'interaction de la boîte de dialogue peut échouer.

Lorsqu'une application Chat ou une fiche Google Chat renvoie une erreur, l'interface Chat affiche le message "Un problème est survenu". ou "Impossible de traiter votre demande." Il peut arriver que l'interface utilisateur de Chat n'affiche aucun message d'erreur, mais que l'application Chat ou la fiche produise un résultat inattendu. Par exemple, un message de fiche peut ne pas s'afficher.

Même si aucun message d'erreur ne s'affiche dans l'UI de Chat, des messages d'erreur descriptifs et des données de journal sont disponibles pour vous aider à corriger les erreurs lorsque la journalisation des erreurs est activée pour les applications Chat. Pour obtenir de l'aide pour afficher, déboguer et corriger les erreurs, consultez Résoudre les erreurs Google Chat.

Applications Chat qui ne sont pas des modules complémentaires : lire les données de formulaire saisies par les utilisateurs sur les fiches

La documentation suivante s'applique aux applications Chat qui ne sont pas des modules complémentaires Google Workspace. Pour migrer une application Chat qui n'est pas un module complémentaire, consultez Convertir une application Google Chat en module complémentaire Google Workspace.

Créer des formulaires à l'aide de fiches

Pour obtenir un exemple d'application Chat qui n'est pas un module complémentaire et qui utilise un formulaire de contact avec une saisie de texte, un sélecteur de date et d'heure, et une saisie de sélection, consultez le code suivant :

Node.js

node/contact-form-app/index.js
/**
 * The section of the contact card that contains the form input widgets. Used in a dialog and card message.
 * To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
 */
const CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": false
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": false
        }
      ]
    }
  }
];

Python

python/contact-form-app/main.py
# The section of the contact card that contains the form input widgets. Used in a dialog and card message.
# To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": False
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": False
        }
      ]
    }
  }
]

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
// The section of the contact card that contains the form input widgets. Used in a dialog and card message.
// To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
final static private List<GoogleAppsCardV1Widget> CONTACT_FORM_WIDGETS = List.of(
  new GoogleAppsCardV1Widget().setTextInput(new GoogleAppsCardV1TextInput()
    .setName("contactName")
    .setLabel("First and last name")
    .setType("SINGLE_LINE")),
  new GoogleAppsCardV1Widget().setDateTimePicker(new GoogleAppsCardV1DateTimePicker()
    .setName("contactBirthdate")
    .setLabel("Birthdate")
    .setType("DATE_ONLY")),
  new GoogleAppsCardV1Widget().setSelectionInput(new GoogleAppsCardV1SelectionInput()
    .setName("contactType")
    .setLabel("Contact type")
    .setType("RADIO_BUTTON")
    .setItems(List.of(
      new GoogleAppsCardV1SelectionItem()
        .setText("Work")
        .setValue("Work")
        .setSelected(false),
      new GoogleAppsCardV1SelectionItem()
        .setText("Personal")
        .setValue("Personal")
        .setSelected(false)))));

Apps Script

apps-script/contact-form-app/contactForm.gs
/**
 * The section of the contact card that contains the form input widgets. Used in a dialog and card message.
 * To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
 */
const CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": false
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": false
        }
      ]
    }
  }
];

Recevoir des données de widgets interactifs

Chaque fois qu'un utilisateur clique sur un bouton, les applications Chat qui ne sont pas des modules complémentaires reçoivent un événement d'interaction en fonction de l'emplacement du bouton :

  • Si le bouton se trouve dans un message ou une boîte de dialogue, les applications Chat qui ne sont pas des modules complémentaires reçoivent un événement d'interaction CARD_CLICKED contenant des informations sur l'interaction. La charge utile des événements d'interaction CARD_CLICKED contient un objet common.formInputs (event.common.formInputs) avec toutes les valeurs saisies par l'utilisateur.

    Vous pouvez récupérer les valeurs de l'objet common.formInputs.WIDGET_NAME, où WIDGET_NAME est le champ name que vous avez spécifié pour le widget. Les valeurs sont renvoyées sous la forme d'un type de données spécifique pour le widget (représenté par un objet Inputs).

    Voici une partie d'un événement d'interaction CARD_CLICKED dans lequel un utilisateur a saisi des valeurs pour chaque widget :

    HTTP

    {
      "type": "CARD_CLICKED",
      "common": { "formInputs": {
        "contactName": { "stringInputs": {
          "value": ["Kai 0"]
        }},
        "contactBirthdate": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }},
        "contactType": { "stringInputs": {
          "value": ["Personal"]
        }}
      }}
    }
    

    Apps Script

    {
      "type": "CARD_CLICKED",
      "common": { "formInputs": {
        "contactName": { "": { "stringInputs": {
          "value": ["Kai 0"]
        }}},
        "contactBirthdate": { "": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }}},
          "contactType": { "": { "stringInputs": {
          "value": ["Personal"]
        }}}
      }}
    }
    
  • Si le bouton se trouve sur une page d'accueil, les applications Chat qui ne sont pas des modules complémentaires reçoivent un événement d'interaction SUBMIT_FORM. La charge utile de l'événement d'interaction contient un objet commonEventObject.formInputs (event.commonEventObject.formInputs) avec toutes les valeurs saisies par l'utilisateur.

    Vous pouvez récupérer les valeurs de l'objet commonEventObject.formInputs.WIDGET_NAME, où WIDGET_NAME est le champ name que vous avez spécifié pour le widget. Les valeurs sont renvoyées sous la forme d'un type de données spécifique pour le widget (représenté par un objet Inputs).

    Voici une partie d'un événement d'interaction SUBMIT_FORM dans lequel un utilisateur a saisi des valeurs pour chaque widget :

    HTTP

    {
      "type": "SUBMIT_FORM",
      "commonEventObject": { "formInputs": {
        "contactName": { "stringInputs": {
          "value": ["Kai 0"]
        }},
        "contactBirthdate": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }},
        "contactType": { "stringInputs": {
          "value": ["Personal"]
        }}
      }}
    }
    

    Apps Script

    {
      "type": "SUBMIT_FORM",
      "commonEventObject": { "formInputs": {
        "contactName": { "": { "stringInputs": {
          "value": ["Kai 0"]
        }}},
        "contactBirthdate": { "": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }}},
          "contactType": { "": { "stringInputs": {
          "value": ["Personal"]
        }}}
      }}
    }
    

Pour recevoir les données, une application Chat qui n'est pas un module complémentaire gère l'événement d'interaction afin d'obtenir les valeurs saisies par les utilisateurs dans les widgets. Le tableau suivant montre comment obtenir la valeur d'un widget de saisie de formulaire donné. Pour chaque widget, le tableau indique le type de données accepté par le widget, l'emplacement de stockage de la valeur dans l'événement d'interaction et un exemple de valeur.

Widget de saisie de formulaire Type de données d'entrée Valeur d'entrée de l'événement d'interaction Exemple de valeur
textInput stringInputs event.common.formInputs.contactName.stringInputs.value[0] Kai O
selectionInput stringInputs Pour obtenir la première ou l'unique valeur, event.common.formInputs.contactType.stringInputs.value[0] Personal
dateTimePicker qui n'accepte que les dates. dateInput event.common.formInputs.contactBirthdate.dateInput.msSinceEpoch. 1000425600000

Transférer les données vers une autre carte

Pour transférer la saisie de données de la fiche initiale dans une application Chat qui n'est pas un module complémentaire, créez le widget button avec des actionParameters contenant le name du widget et la valeur saisie par l'utilisateur, comme illustré dans l'exemple suivant :

Node.js

node/contact-form-app/index.js
buttonList: { buttons: [{
  text: "Submit",
  onClick: { action: {
    function: "submitForm",
    parameters: [{
      key: "contactName", value: name }, {
      key: "contactBirthdate", value: birthdate }, {
      key: "contactType", value: type
    }]
  }}
}]}

Python

python/contact-form-app/main.py
'buttonList': { 'buttons': [{
  'text': "Submit",
  'onClick': { 'action': {
    'function': "submitForm",
    'parameters': [{
      'key': "contactName", 'value': name }, {
      'key': "contactBirthdate", 'value': birthdate }, {
      'key': "contactType", 'value': type
    }]
  }}
}]}

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
new GoogleAppsCardV1Widget().setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(new GoogleAppsCardV1Button()
  .setText("Submit")
  .setOnClick(new GoogleAppsCardV1OnClick().setAction(new GoogleAppsCardV1Action()
    .setFunction("submitForm")
    .setParameters(List.of(
      new GoogleAppsCardV1ActionParameter().setKey("contactName").setValue(name),
      new GoogleAppsCardV1ActionParameter().setKey("contactBirthdate").setValue(birthdate),
      new GoogleAppsCardV1ActionParameter().setKey("contactType").setValue(type))))))))));

Apps Script

apps-script/contact-form-app/main.gs
buttonList: { buttons: [{
  text: "Submit",
  onClick: { action: {
    function: "submitForm",
    parameters: [{
      key: "contactName", value: name }, {
      key: "contactBirthdate", value: birthdate }, {
      key: "contactType", value: type
    }]
  }}
}]}

Lorsqu'un utilisateur clique sur le bouton, l'application Chat qui n'est pas un module complémentaire reçoit un événement d'interaction CARD_CLICKED à partir duquel vous pouvez recevoir des données.

Répondre à l'envoi d'un formulaire

Dans l'exemple suivant, une application Chat qui n'est pas un module complémentaire envoie un message texte pour confirmer qu'elle a bien reçu un formulaire envoyé à partir d'une boîte de dialogue ou d'un message de fiche :

Node.js

node/contact-form-app/index.js
const contactName = event.common.parameters["contactName"];
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
const errorMessage = "Don't forget to name your new contact!";
if (!contactName && event.dialogEventType === "SUBMIT_DIALOG") {
  return { actionResponse: {
    type: "DIALOG",
    dialogAction: { actionStatus: {
      statusCode: "INVALID_ARGUMENT",
      userFacingMessage: errorMessage
    }}
  }};
}

Python

python/contact-form-app/main.py
contact_name = event.get('common').get('parameters')["contactName"]
# Checks to make sure the user entered a contact name.
# If no name value detected, returns an error message.
error_message = "Don't forget to name your new contact!"
if contact_name == "" and "SUBMIT_DIALOG" == event.get('dialogEventType'):
  return { 'actionResponse': {
    'type': "DIALOG",
    'dialogAction': { 'actionStatus': {
      'statusCode': "INVALID_ARGUMENT",
      'userFacingMessage': error_message
    }}
  }}

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
String contactName = event.at("/common/parameters/contactName").asText();
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
String errorMessage = "Don't forget to name your new contact!";
if (contactName.isEmpty() && event.at("/dialogEventType") != null && "SUBMIT_DIALOG".equals(event.at("/dialogEventType").asText())) {
  return new Message().setActionResponse(new ActionResponse()
    .setType("DIALOG")
    .setDialogAction(new DialogAction().setActionStatus(new ActionStatus()
      .setStatusCode("INVALID_ARGUMENT")
      .setUserFacingMessage(errorMessage))));
}

Apps Script

apps-script/contact-form-app/main.gs
const contactName = event.common.parameters["contactName"];
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
const errorMessage = "Don't forget to name your new contact!";
if (!contactName && event.dialogEventType === "SUBMIT_DIALOG") {
  return { actionResponse: {
    type: "DIALOG",
    dialogAction: { actionStatus: {
      statusCode: "INVALID_ARGUMENT",
      userFacingMessage: errorMessage
    }}
  }};
}

Pour traiter et fermer une boîte de dialogue dans une application Chat qui n'est pas un module complémentaire, renvoyez un objet ActionResponse qui indique si vous souhaitez envoyer un message de confirmation, mettre à jour le message ou la fiche d'origine, ou simplement fermer la boîte de dialogue. Pour connaître la procédure à suivre, consultez Fermer une boîte de dialogue.