Aggiungere elementi interattivi dell'interfaccia utente alle schede

Questa pagina spiega come aggiungere widget ed elementi dell'interfaccia utente alle schede in modo che gli utenti possano interagire con la tua app Google Chat, ad esempio facendo clic su un pulsante o inviando informazioni.

Le app di chat possono utilizzare le seguenti interfacce di chat per creare schede interattive:

  • Messaggi che contengono una o più schede.
  • Home page, che è una scheda che viene visualizzata nella scheda Home dei messaggi diretti con l'app Chat.
  • Finestre di dialogo, ovvero schede che si aprono in una nuova finestra da messaggi e home page.

Quando gli utenti interagiscono con le schede, le app di chat possono utilizzare i dati che ricevono per elaborarli e rispondere di conseguenza. Per maggiori dettagli, vedi Raccogliere ed elaborare le informazioni degli utenti di Google Chat.


Utilizza Card Builder per progettare e visualizzare in anteprima le interfacce utente e di messaggistica per le app di chat:

Apri il generatore di schede

Prerequisiti

Un'app Google Chat configurata per ricevere e rispondere alle interazioni degli utenti. Per creare un'app di chat interattiva, completa uno dei seguenti quickstart in base all'architettura dell'app che vuoi utilizzare:

Aggiungere un pulsante

Il widget ButtonList mostra un insieme di pulsanti. I pulsanti possono visualizzare testo, un'icona o sia testo che icona. Ogni Button supporta un'azione OnClick che si verifica quando gli utenti fanno clic sul pulsante. Ad esempio:

  • Apri un link ipertestuale con OpenLink, per fornire agli utenti ulteriori informazioni.
  • Esegui un action che esegue una funzione personalizzata, ad esempio la chiamata di un'API.

Per l'accessibilità, i pulsanti supportano il testo alternativo.

Aggiungere un pulsante che esegue una funzione personalizzata

Di seguito è riportata una scheda costituita da un widget ButtonList con due pulsanti. Un pulsante apre la documentazione per lo sviluppo di Google Chat in una nuova scheda. L'altro pulsante esegue una funzione personalizzata chiamata goToView() e passa il parametro viewType="BIRD EYE VIEW".

Aggiungere un pulsante con lo stile Material Design

Di seguito viene visualizzato un insieme di pulsanti in diversi stili di pulsanti Material Design.

Per applicare lo stile Material Design, non includere l'attributo "colore".

Aggiungi un pulsante con un colore personalizzato e un pulsante disattivato

Puoi impedire agli utenti di fare clic su un pulsante impostando "disabled": "true".

Di seguito viene visualizzata una scheda costituita da un widget ButtonList con due pulsanti. Un pulsante utilizza il campo Color per personalizzare il colore di sfondo del pulsante. L'altro pulsante viene disattivato con il campo Disabled, che impedisce all'utente di fare clic sul pulsante ed eseguire la funzione.

Aggiungere un pulsante con un'icona

Di seguito viene visualizzata una scheda composta da un widget ButtonList con due widget Button con icone. Un pulsante utilizza il campo knownIcon per visualizzare l'icona email integrata di Google Chat. L'altro pulsante utilizza il campo iconUrl per visualizzare un widget icona personalizzata.

Aggiungere un pulsante con un'icona e del testo

Di seguito è mostrata una scheda composta da un widget ButtonList che chiede all'utente di inviare un'email. Il primo pulsante mostra un'icona email e il secondo pulsante mostra del testo. L'utente può fare clic sull'icona o sul pulsante di testo per eseguire la funzione sendEmail.

Personalizzare il pulsante per una sezione comprimibile

Personalizza il pulsante di controllo che comprime ed espande le sezioni all'interno di una scheda. Scegli tra una gamma di icone o immagini per rappresentare visivamente i contenuti della sezione, in modo che gli utenti possano comprendere e interagire più facilmente con le informazioni.

Aggiungere un menu extra

Il Overflow menu può essere utilizzato nelle schede di Chat per offrire opzioni e azioni aggiuntive. Ti consente di includere più opzioni senza ingombrare l'interfaccia della scheda, garantendo un design pulito e organizzato.

Aggiungere un elenco di chip

Il widget ChipList offre un modo versatile e visivamente accattivante per visualizzare le informazioni. Utilizza gli elenchi di chip per rappresentare tag, categorie o altri dati pertinenti, in modo che gli utenti possano navigare e interagire più facilmente con i tuoi contenuti.

Raccogliere informazioni dagli utenti

Questa sezione spiega come aggiungere widget che raccolgono informazioni, ad esempio testo o selezioni.

Per scoprire come elaborare ciò che inseriscono gli utenti, consulta Raccogliere ed elaborare le informazioni degli utenti di Google Chat.

Raccogliere testo

Il widget TextInput fornisce un campo in cui gli utenti possono inserire testo. Il widget supporta i suggerimenti, che aiutano gli utenti a inserire dati uniformi, e le azioni on-change, che sono Actions che vengono eseguite quando si verifica una modifica nel campo di immissione di testo, ad esempio quando un utente aggiunge o elimina del testo.

Quando devi raccogliere dati astratti o sconosciuti dagli utenti, utilizza questo widget TextInput. Per raccogliere i dati definiti dagli utenti, utilizza il widget SelectionInput.

Di seguito è riportata una scheda costituita da un widget TextInput:

Raccogliere date o orari

Il widget DateTimePicker consente agli utenti di inserire una data, un'ora o entrambe. In alternativa, gli utenti possono utilizzare il selettore per selezionare date e orari. Se gli utenti inseriscono una data o un'ora non valide, il selettore mostra un errore che invita gli utenti a inserire le informazioni correttamente.

Di seguito viene visualizzata una scheda composta da tre diversi tipi di widget DateTimePicker:

Consentire agli utenti di selezionare gli elementi

Il widget SelectionInput fornisce un insieme di elementi selezionabili, come caselle di controllo, pulsanti di opzione, interruttori o un menu a discesa. Puoi utilizzare questo widget per raccogliere dati definiti e standardizzati dagli utenti. Per raccogliere dati non definiti dagli utenti, utilizza invece il widget TextInput.

Il widget SelectionInput supporta i suggerimenti, che aiutano gli utenti a inserire dati uniformi, e le azioni on-change, che sono Actions che vengono eseguite quando si verifica una modifica in un campo di immissione di selezione, ad esempio quando un utente seleziona o deseleziona un elemento.

Le app di chat possono ricevere ed elaborare il valore degli articoli selezionati. Per informazioni dettagliate sull'utilizzo degli input dei moduli, vedi Elaborare le informazioni inserite dagli utenti.

Questa sezione fornisce esempi di schede che utilizzano il widget SelectionInput. Gli esempi utilizzano diversi tipi di input di sezione:

Aggiungere una casella di controllo

Di seguito è mostrata una scheda che chiede all'utente di specificare se un contatto è professionale, personale o entrambi, con un widget SelectionInput che utilizza le caselle di controllo:

Aggiungere un pulsante di opzione

Di seguito viene visualizzata una scheda che chiede all'utente di specificare se un contatto è professionale o personale con un widget SelectionInput che utilizza pulsanti di opzione:

Aggiungere un interruttore

Di seguito viene visualizzata una scheda che chiede all'utente di specificare se un contatto è professionale, personale o entrambi con un widget SelectionInput che utilizza i pulsanti di attivazione/disattivazione:

Di seguito viene visualizzata una scheda che chiede all'utente di specificare se un contatto è professionale o personale con un widget SelectionInput che utilizza un menu a discesa:

Compilare dinamicamente i menu a discesa

Disponibile per le app Google Chat.

Puoi compilare dinamicamente gli elementi di un menu a discesa dalle origini dati in Google Workspace o da un'origine dati esterna. Per utilizzare le origini dati dinamiche, specifica il campo data_source_configs, che è un array di oggetti DataSourceConfig. Ogni DataSourceConfig può contenere un platformDataSource o un remoteDataSource. Al momento è supportato un solo DataSourceConfig.

Compilare gli elementi da Google Workspace

Per compilare gli elementi dalle origini dati di Google Workspace, ad esempio gli utenti di Google Workspace, specifica il campo platformDataSource all'interno di un DataSourceConfig. A differenza dell'utilizzo di items statici, ometti gli oggetti SelectionItem, perché questi elementi di selezione vengono recuperati dinamicamente da Google Workspace.

Il seguente codice mostra un menu a discesa che compila gli utenti di 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
              }
            ]
          }
        }
      ]
    }
  ]
}
Compilare gli elementi da un'origine dati esterna

Per compilare gli elementi da un'origine dati esterna o di terze parti, ad esempio un sistema di gestione dei rapporti con i clienti (CRM), utilizza il campo remoteDataSource all'interno di un DataSourceConfig per specificare una funzione che restituisce gli elementi dall'origine dati.

Il seguente codice mostra un menu a discesa che popola gli elementi da un insieme esterno di contatti eseguendo la funzione 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"
              }
            ]
          }
        }
      ]
    }
  ]
}

Per ridurre le richieste a un'origine dati dinamica, puoi includere gli elementi suggeriti che vengono visualizzati nel menu a discesa prima che gli utenti digitino. Puoi anche configurare il menu a discesa in modo che completi automaticamente gli elementi in base a ciò che digitano gli utenti impostando min_characters_trigger all'interno di DataSourceConfig. Quando un utente digita almeno il numero di caratteri specificato in min_characters_trigger, viene attivata la funzione specificata in remoteDataSource. L'oggetto evento passato alla tua funzione include l'input dell'utente nella chiave autocomplete_widget_query.

Aggiungere un menu a selezione multipla

Di seguito è mostrata una scheda che chiede all'utente di selezionare i contatti da un menu a selezione multipla:

Puoi compilare gli elementi di un menu a selezione multipla dalle seguenti origini dati in Google Workspace:

  • Utenti di Google Workspace: puoi popolare solo gli utenti all'interno della stessa organizzazione Google Workspace.
  • Spazi di chat: l'utente che inserisce elementi nel menu a selezione multipla può visualizzare e selezionare solo gli spazi a cui appartiene all'interno della sua organizzazione Google Workspace.

Per utilizzare le origini dati di Google Workspace, specifica il campo platformDataSource. A differenza di altri tipi di input di selezione, ometti gli oggetti SelectionItem, perché questi elementi di selezione vengono recuperati dinamicamente da Google Workspace.

Il seguente codice mostra un menu a selezione multipla degli utenti di Google Workspace. Per compilare gli utenti, l'input di selezione imposta commonDataSource su USER:

JSON

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

Il seguente codice mostra un menu a selezione multipla degli spazi Chat. Per compilare gli spazi, l'input di selezione specifica il campo hostAppDataSource. Il menu di selezione multipla imposta anche defaultToCurrentSpace su true, il che rende lo spazio attuale la selezione predefinita nel menu:

JSON

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

I menu a selezione multipla possono anche compilare elementi da un'origine dati esterna o di terze parti. Ad esempio, puoi utilizzare i menu a selezione multipla per aiutare un utente a scegliere da un elenco di lead di vendita di un sistema di gestione dei rapporti con i clienti (CRM).

Per utilizzare un'origine dati esterna, utilizza il campo externalDataSource per specificare una funzione che restituisce elementi dall'origine dati.

Per ridurre le richieste a un'origine dati esterna, puoi includere gli elementi suggeriti che vengono visualizzati nel menu a selezione multipla prima che gli utenti digitino nel menu. Ad esempio, puoi compilare i contatti cercati di recente per l'utente. Per compilare gli elementi suggeriti da un'origine dati esterna, specifica gli oggetti SelectionItem.

Il seguente esempio di codice mostra un menu a selezione multipla che esegue query e compila gli elementi da un'origine dati esterna:

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

Sostituisci FUNCTION_URL con l'endpoint HTTP che esegue query sull'origine dati esterna.

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

Sostituisci FUNCTION_URL con l'endpoint HTTP che esegue query sull'origine dati esterna.

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

Sostituisci FUNCTION_URL con l'endpoint HTTP che esegue query sull'origine dati esterna.

Apps Script

Questo esempio invia un messaggio della scheda restituendo JSON della scheda. Puoi anche utilizzare il servizio di schede 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")]
}

Compilare gli elementi suggeriti da un'origine dati dinamica

Per le origini dati esterne, puoi anche completare automaticamente e suggerire elementi che gli utenti iniziano a digitare in un menu a selezione multipla o in un menu a discesa. Ad esempio, se un utente inizia a digitare Atl per un menu che popola le città degli Stati Uniti, la tua app Chat può suggerire automaticamente Atlanta prima che l'utente finisca di digitare. Puoi suggerire fino a 100 elementi.

Per restituire gli elementi suggeriti, la funzione che esegue query sull'origine dati esterna deve:

  1. Gestisci un oggetto evento, che l'app Chat riceve quando gli utenti digitano nel menu.
  2. Dall'oggetto evento, recupera il valore digitato dall'utente, che è rappresentato nel campo event.commonEventObject.parameters["autocomplete_widget_query"].
  3. Esegui una query sull'origine dati utilizzando il valore inserito dall'utente per ottenere uno o più SelectionItems da suggerire all'utente.
  4. Restituisci gli elementi suggeriti restituendo l'azione RenderActions con un oggetto modifyCard.

Il seguente esempio di codice mostra come un'app Chat suggerisce dinamicamente elementi nel menu a selezione multipla di una scheda. Quando un utente digita nel menu, la funzione o l'endpoint fornito nel campo externalDataSource del widget esegue una query su un'origine dati esterna e suggerisce elementi che l'utente può selezionare:

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

Sostituisci FUNCTION_URL con l'endpoint HTTP che esegue query sull'origine dati esterna.

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
  }

Sostituisci FUNCTION_URL con l'endpoint HTTP che esegue query sull'origine dati esterna.

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

Sostituisci FUNCTION_URL con l'endpoint HTTP che esegue query sull'origine dati esterna.

Apps Script

Questo esempio invia un messaggio della scheda restituendo JSON della scheda. Puoi anche utilizzare il servizio di schede 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
  };
}

Convalidare i dati inseriti nelle schede

Questa pagina spiega come convalidare i dati inseriti in un action e nei widget di una scheda. Ad esempio, puoi verificare che in un campo di immissione di testo sia stato inserito del testo dall'utente o che contenga un determinato numero di caratteri.

Impostare i widget richiesti per le azioni

Nell'ambito di action della scheda, aggiungi i nomi dei widget necessari per un'azione all'elenco requiredWidgets.

Se uno dei widget elencati qui non ha un valore quando viene richiamata questa azione, l'invio dell'azione del modulo viene annullato.

Quando "all_widgets_are_required": "true" è impostato per un'azione, tutti i widget nella scheda sono richiesti da questa azione.

Impostare un'azione all_widgets_are_required nella selezione multipla

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
              }
            ]
          }
        }
      ]
    }
  ]
}
Imposta un'azione all_widgets_are_required in 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"
          }
        }
      ]
    }
  ]
}
Imposta un'azione all_widgets_are_required nel menu a discesa

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

Impostare la convalida per un widget di input di testo

Nel campo di convalida del widget textInput, è possibile specificare il limite di caratteri e il tipo di input per questo widget di input di testo.

Impostare un limite di caratteri per un widget di input di testo

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
            }
          }
        }
      ]
    }
  ]
}
Impostare il tipo di input per un widget di input di testo

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

Risoluzione dei problemi

Quando un'app Google Chat o una scheda restituisce un errore, l'interfaccia di Chat mostra il messaggio "Si è verificato un problema". o "Impossibile elaborare la richiesta". A volte l'interfaccia utente di Chat non mostra alcun messaggio di errore, ma l'app o la scheda Chat produce un risultato imprevisto; ad esempio, un messaggio della scheda potrebbe non essere visualizzato.

Anche se nell'interfaccia utente di Chat potrebbe non essere visualizzato un messaggio di errore, sono disponibili messaggi di errore descrittivi e dati di log per aiutarti a correggere gli errori quando la registrazione degli errori per le app di chat è attivata. Per assistenza nella visualizzazione, nel debug e nella correzione degli errori, consulta Risolvere e correggere gli errori di Google Chat.

App di chat che non sono componenti aggiuntivi: progetta schede e dialoghi interattivi

La seguente documentazione si applica alle app di Chat che non sono componenti aggiuntivi di Google Workspace. Per eseguire la migrazione di un'app di Chat che non è un componente aggiuntivo, vedi Convertire un'app Google Chat in un componente aggiuntivo di Google Workspace.

Il seguente codice mostra un menu a selezione multipla di elementi di un insieme esterno di contatti per l'utente in un'app di chat che non è un componente aggiuntivo. Il menu mostra un contatto per impostazione predefinita ed esegue la funzione getContacts per recuperare e compilare gli elementi dall'origine dati esterna:

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

Per completare automaticamente gli elementi in un'app di chat che non è un componente aggiuntivo, crea una funzione che esegue query sull'origine dati esterna e restituisce gli elementi ogni volta che un utente digita nel menu a selezione multipla. La funzione deve:

  • Passa un oggetto evento che rappresenta l'interazione dell'utente con il menu.
  • Identifica che il valore invokedFunction dell'evento di interazione corrisponde alla funzione del campo externalDataSource.
  • Quando le funzioni corrispondono, restituisci gli elementi suggeriti dall'origine dati esterna. Per suggerire elementi in base a ciò che digita l'utente, recupera il valore della chiave autocomplete_widget_query. Questo valore rappresenta ciò che l'utente digita nel menu.

Il seguente codice completa automaticamente gli elementi di una risorsa dati esterna. Utilizzando l'esempio precedente, l'app Chat che non è un componente aggiuntivo suggerisce elementi in base a quando viene attivata la funzione 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);
}

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