Ajouter des éléments d'interface utilisateur interactifs aux fiches

Cette page explique comment ajouter des widgets et des éléments d'interface utilisateur aux fiches pour permettre aux utilisateurs d'interagir avec votre application Google Chat, par exemple en cliquant sur un bouton ou en envoyant des informations.

Les applications Chat peuvent utiliser les interfaces Chat suivantes pour créer des fiches interactives :

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

Lorsque les utilisateurs interagissent avec des fiches, les applications Chat peuvent utiliser les données qu'elles reçoivent pour les traiter et y répondre en conséquence. Pour en savoir plus, consultez Collecter et traiter les informations des utilisateurs Google Chat.


Utilisez Card Builder pour concevoir et prévisualiser les messages et les interfaces utilisateur des applications Chat :

Ouvrez le générateur de cartes.

Prérequis

Une application Google Chat configurée pour recevoir des événements d'interaction et y répondre. Pour créer une application Chat interactive, suivez l'un des guides de démarrage rapide ci-dessous en fonction de l'architecture d'application que vous souhaitez utiliser :

Ajouter un bouton

Le widget ButtonList affiche un ensemble de boutons. Les boutons peuvent afficher du texte, une icône ou les deux. Chaque Button est compatible avec une OnClick action qui se produit lorsque les utilisateurs cliquent sur le bouton. Exemple :

  • Ouvrez un lien hypertexte avec OpenLink pour fournir aux utilisateurs des informations supplémentaires.
  • Exécutez un action qui exécute une fonction personnalisée, comme l'appel d'une API.

Pour l'accessibilité, les boutons sont compatibles avec le texte alternatif.

Ajouter un bouton qui exécute une fonction personnalisée

Voici une fiche composée d'un widget ButtonList avec deux boutons. Un bouton permet d'ouvrir la documentation pour les développeurs Google Chat dans un nouvel onglet. L'autre bouton exécute une fonction personnalisée appelée goToView() et transmet le paramètre viewType="BIRD EYE VIEW".

Ajouter un bouton avec le style Material Design

L'exemple suivant affiche un ensemble de boutons dans différents styles de boutons Material Design.

Pour appliquer le style Material Design, n'incluez pas l'attribut "color".

Ajouter un bouton avec une couleur personnalisée et un bouton désactivé

Vous pouvez empêcher les utilisateurs de cliquer sur un bouton en définissant "disabled": "true".

L'exemple suivant affiche une fiche composée d'un widget ButtonList avec deux boutons. Un bouton utilise le champ Color pour personnaliser la couleur d'arrière-plan du bouton. L'autre bouton est désactivé avec le champ Disabled, ce qui empêche l'utilisateur de cliquer dessus et d'exécuter la fonction.

Ajouter un bouton avec une icône

L'exemple suivant affiche une fiche composée d'un widget ButtonList avec deux widgets Button d'icônes. Un bouton utilise le champ knownIcon pour afficher l'icône d'e-mail intégrée de Google Chat. L'autre bouton utilise le champ iconUrl pour afficher un widget d'icône personnalisée.

Ajouter un bouton avec une icône et du texte

L'exemple suivant affiche une fiche composée d'un widget ButtonList qui invite l'utilisateur à envoyer un e-mail. Le premier bouton affiche une icône d'e-mail et le second affiche du texte. L'utilisateur peut cliquer sur l'icône ou sur le bouton de texte pour exécuter la fonction sendEmail.

Personnaliser le bouton d'une section réductible

Personnalisez le bouton de contrôle qui réduit et agrandit les sections d'une fiche. Choisissez parmi plusieurs icônes ou images pour représenter visuellement le contenu de la section, afin d'aider les utilisateurs à comprendre les informations et à s'en servir.

Ajouter un menu à développer

Le Overflow menu peut être utilisé dans les fiches Chat pour offrir d'autres options et actions. Il vous permet d'inclure plus d'options sans encombrer l'interface de la fiche, pour un design épuré et organisé.

Ajouter une liste de chips

Le widget ChipList offre un moyen polyvalent et visuellement attrayant d'afficher des informations. Utilisez des listes de chips pour représenter des tags, des catégories ou d'autres données utiles, et faciliter ainsi la navigation et l'interaction avec vos contenus pour les utilisateurs.

Collecter des informations auprès des utilisateurs

Cette section explique comment ajouter des widgets qui collectent des informations, comme du texte ou des sélections.

Pour savoir comment traiter les entrées des utilisateurs, consultez Collecter et traiter les informations des utilisateurs Google Chat.

Collecter du texte

Le widget TextInput fournit un champ dans lequel les utilisateurs peuvent saisir du texte. Le widget est compatible avec les suggestions, qui aident les utilisateurs à saisir des données uniformes, et avec les actions "on-change", qui sont des Actions qui s'exécutent lorsqu'une modification se produit dans le champ de saisie de texte, par exemple lorsqu'un utilisateur ajoute ou supprime du texte.

Utilisez ce widget TextInput lorsque vous devez collecter des données abstraites ou inconnues auprès des utilisateurs. Pour collecter des données définies auprès des utilisateurs, utilisez plutôt le widget SelectionInput.

Voici une fiche composée d'un widget TextInput :

Collecter des dates ou des heures

Le widget DateTimePicker permet aux utilisateurs de saisir une date, une heure ou les deux. Les utilisateurs peuvent également utiliser le sélecteur pour choisir des dates et des heures. Si les utilisateurs saisissent une date ou une heure non valides, le sélecteur affiche une erreur qui les invite à saisir les informations correctement.

L'exemple suivant affiche une fiche composée de trois types différents de widgets DateTimePicker :

Autoriser les utilisateurs à sélectionner des éléments

Le widget SelectionInput fournit un ensemble d'éléments sélectionnables, tels que des cases à cocher, des cases d'option, des boutons bascule ou un menu déroulant. Vous pouvez utiliser ce widget pour collecter des données définies et standardisées auprès des utilisateurs. Pour collecter des données non définies auprès des utilisateurs, utilisez plutôt le widget TextInput.

Le widget SelectionInput est compatible avec les suggestions, qui aident les utilisateurs à saisir des données uniformes, et avec les actions "on-change", qui sont des Actions qui s'exécutent lorsqu'une modification se produit dans un champ de saisie de sélection, par exemple lorsqu'un utilisateur sélectionne ou désélectionne un élément.

Les applications de chat peuvent recevoir et traiter la valeur des éléments sélectionnés. Pour en savoir plus sur l'utilisation des entrées de formulaire, consultez Traiter les informations saisies par les utilisateurs.

Cette section fournit des exemples de cartes qui utilisent le widget SelectionInput. Les exemples utilisent différents types d'entrées de section :

Ajouter une case à cocher

L'exemple suivant affiche une fiche qui demande à l'utilisateur de spécifier si un contact est professionnel, personnel ou les deux, avec un widget SelectionInput qui utilise des cases à cocher :

Ajouter un bouton radio

L'exemple suivant affiche une fiche qui demande à l'utilisateur de préciser si un contact est professionnel ou personnel à l'aide d'un widget SelectionInput qui utilise des boutons radio :

Ajouter un bouton bascule

L'exemple suivant affiche une fiche qui demande à l'utilisateur de spécifier si un contact est professionnel, personnel ou les deux, avec un widget SelectionInput qui utilise des boutons bascule :

L'exemple suivant affiche une fiche qui demande à l'utilisateur de préciser si un contact est professionnel ou personnel à l'aide d'un widget SelectionInput qui utilise un menu déroulant :

Ajouter un menu à sélection multiple

L'exemple suivant affiche une fiche qui demande à l'utilisateur de sélectionner des contacts dans un menu à sélection multiple :

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

  • Utilisateurs Google Workspace : vous ne pouvez ajouter que des utilisateurs appartenant à la même organisation Google Workspace.
  • Espaces de discussion : l'utilisateur qui saisit des éléments dans le menu à sélection multiple ne peut afficher et sélectionner que les espaces auxquels il appartient dans son organisation Google Workspace.

Pour utiliser les sources de données Google Workspace, vous devez spécifier le champ platformDataSource. Contrairement aux autres types d'entrée 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 à sélection multiple des utilisateurs Google Workspace. Pour remplir la liste des utilisateurs, la sélection d'entrée 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 affiche un menu à sélection multiple des espaces de discussion. Pour remplir les espaces, la sélection d'entrée spécifie le champ hostAppDataSource. Le menu à 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
          }
        }
      }
    }
  }
}

Les menus à sélection multiple peuvent également remplir des éléments à partir d'une source de données tierce ou externe. Par exemple, vous pouvez utiliser des menus à sélection multiple pour aider un utilisateur à choisir parmi une liste de prospects commerciaux provenant d'un système de gestion de la relation client (CRM).

Pour utiliser une source de données externe, vous devez utiliser le champ externalDataSource pour spécifier une fonction qui renvoie des éléments de la source de données.

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

Le code suivant affiche un menu à sélection multiple d'éléments provenant d'un ensemble externe de contacts pour l'utilisateur. Le menu affiche un contact par défaut et exécute la fonction getContacts pour récupérer et remplir les éléments de la source de données externe :

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

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

Pour les sources de données externes, vous pouvez également saisir automatiquement les éléments que les utilisateurs commencent à saisir dans le menu à sélection multiple. Par exemple, si un utilisateur commence à saisir Atl pour un menu qui affiche les villes des États-Unis, votre application Chat peut suggérer automatiquement Atlanta avant que l'utilisateur ait fini de saisir le texte. Vous pouvez saisir automatiquement jusqu'à 100 éléments.

Pour compléter automatiquement les éléments, vous devez créer une fonction qui interroge la source de données externe et renvoie les éléments chaque fois qu'un utilisateur saisit du texte dans le menu à sélection multiple. La fonction doit effectuer les opérations suivantes :

  • Transmettez un objet événement qui représente l'interaction de l'utilisateur avec le menu.
  • Identifiez que la valeur invokedFunction de l'événement d'interaction correspond à la fonction du champ externalDataSource.
  • Lorsque les fonctions correspondent, renvoyez les éléments suggérés à partir de la source de données externe. Pour suggérer des éléments en fonction de ce que l'utilisateur saisit, obtenez la valeur de la clé autocomplete_widget_query. Cette valeur représente ce que l'utilisateur saisit dans le menu.

Le code suivant complète automatiquement les éléments d'une ressource de données externe. En reprenant l'exemple précédent, l'application de chat suggère des éléments en fonction du moment où la fonction getContacts est déclenchée :

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

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

Valider les données saisies dans les cartes

Cette page explique comment valider les données saisies dans les action et les widgets d'une fiche. Par exemple, vous pouvez vérifier qu'un champ de saisie de texte contient du texte saisi par l'utilisateur ou qu'il contient un certain nombre de caractères.

Définir les widgets requis pour les actions

Dans le action de la fiche, ajoutez les noms des widgets dont une action a besoin à sa liste requiredWidgets.

Si l'un des widgets listés ici n'a pas de valeur lorsque cette action est appelée, l'envoi de l'action de formulaire est annulé.

Lorsque "all_widgets_are_required": "true" est défini pour une action, tous les widgets de la fiche sont requis par cette action.

Définir une action all_widgets_are_required en sélection multiple

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
              }
            ]
          }
        }
      ]
    }
  ]
}
Définir une action all_widgets_are_required dans 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"
          }
        }
      ]
    }
  ]
}
Définir une action all_widgets_are_required dans le menu déroulant

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

Définir la validation pour un widget de saisie de texte

Dans le champ de validation du widget textInput, il peut spécifier la limite de caractères et le type d'entrée pour ce widget de saisie de texte.

Définir une limite de caractères pour un widget de saisie de texte

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
            }
          }
        }
      ]
    }
  ]
}
Définir le type de saisie pour un widget de saisie de texte

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

Résoudre les problèmes

Lorsqu'une application ou une fiche Google Chat renvoie une erreur, l'interface Chat affiche le message "Une erreur s'est produite". ou "Impossible de traiter votre demande". Il arrive que l'UI de Chat n'affiche aucun message d'erreur, mais que l'application ou la fiche Chat produise un résultat inattendu (par exemple, un message de fiche peut ne pas s'afficher).

Bien qu'un message d'erreur ne s'affiche pas dans l'interface utilisateur de Chat, des messages d'erreur descriptifs et des données de journaux sont disponibles pour vous aider à corriger les erreurs lorsque la journalisation des erreurs pour les applications Chat est activée. Pour obtenir de l'aide concernant l'affichage, le débogage et la résolution des erreurs, consultez Résoudre les problèmes et corriger les erreurs Google Chat.