Criar um card de configuração para uma etapa

Neste guia, explicamos como criar um card de configuração que permite aos usuários personalizar e fornecer entradas para uma etapa no Google Workspace Studio.

Em geral, para criar um card de configuração, você cria uma interface de card como faria para qualquer outro complemento do Google Workspace. Para ajuda na criação de interfaces de card de configuração, consulte:

  • O Card Builder, uma ferramenta interativa que ajuda você a criar e definir cards.
  • Card na documentação de referência da API Google Workspace Add-ons.
  • O Card Service, um serviço do Apps Script que permite que os scripts configurem e criem cards.
  • Interfaces baseadas em cards na documentação para desenvolvedores de complementos do Google Workspace.

Alguns widgets de card têm funcionalidades e recursos especiais específicos do Workspace Studio, detalhados neste guia.

Definir um card de configuração

Defina um card de configuração no manifesto do Apps Script e no código.

O exemplo a seguir mostra como criar um card de configuração que pede aos usuários para selecionar um espaço do Google Chat.

Editar o arquivo de manifesto

No arquivo de manifesto, defina workflowElements.

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Chat space selector",
      "logoUrl": "https://www.gstatic.com/images/branding/productlogos/gsuite_addons/v6/web-24dp/logo_gsuite_addons_color_1x_web_24dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "actionElement",
          "state": "ACTIVE",
          "name": "Chat space selector",
          "description": "Lets the user select a space from Google  Chat",
          "workflowAction": {
            "inputs": [
              {
                "id": "chooseSpace",
                "description": "Choose a Chat space",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfigSpacePicker",
            "onExecuteFunction": "onExecuteSpacePicker"
          }
        }
      ]
    }
  }
}

Editar o código

No código do aplicativo, retorne um card.

Apps Script

/**
 * Generates and displays a configuration card to choose a Chat space
 */
function onConfigSpacePicker() {

  const selectionInput = CardService.newSelectionInput()
    .setTitle("First Value")
    .setFieldName("chooseSpace")
    .setType(CardService.SelectionInputType.MULTI_SELECT)
    .setPlatformDataSource(
      CardService.newPlatformDataSource()
        .setHostAppDataSource(
          CardService.newHostAppDataSource()
            .setWorkflowDataSource(
              CardService.newWorkflowDataSource()
                .setIncludeVariables(true)
                .setType(CardService.WorkflowDataSourceType.SPACE)
            )
        )
    );

  const cardSection = CardService.newCardSection()
    .setHeader("Select Chat Space")
    .setId("section_1")
    .addWidget(selectionInput)

  var card = CardService.newCardBuilder()
    .addSection(cardSection)
    .build();

  return card;
}

function onExecuteSpacePicker(e) {
}

Configurar o preenchimento automático para widgets de entrada

É possível configurar o preenchimento automático para widgets de SelectionInput e ajudar os usuários a selecionar uma opção em uma lista. Por exemplo, se um usuário começar a digitar Atl em um menu que preenche cidades nos Estados Unidos, seu elemento poderá sugerir automaticamente Atlanta antes que o usuário termine de digitar. É possível usar o preenchimento automático em até 100 itens.

As sugestões de preenchimento automático podem vir das seguintes fontes de dados:

  • Autocompletar do lado do servidor:as sugestões são preenchidas com base em uma fonte de dados externa ou de terceiros definida por você.
  • Dados do Google Workspace:as sugestões são geradas com base em fontes do Google Workspace, como usuários do Google Workspace ou espaços do Google Chat.

Preenchimento automático do lado do servidor

É possível configurar um widget de SelectionInput para preencher automaticamente sugestões de uma fonte de dados externa. Por exemplo, você pode ajudar os usuários a selecionar em uma lista de leads de vendas de um sistema de gestão de relacionamento com o cliente (CRM).

Para implementar o preenchimento automático do lado do servidor, você precisa:

  1. Defina a fonte de dados:no widget SelectionInput, adicione um DataSourceConfig que especifica um RemoteDataSource. Essa configuração aponta para uma função do Apps Script que busca sugestões de preenchimento automático.
  2. Implemente a função de preenchimento automático:essa função é acionada quando o usuário digita no campo de entrada. A função precisa consultar sua fonte de dados externa com base na entrada do usuário e retornar uma lista de sugestões.

O exemplo a seguir mostra como configurar um widget SelectionInput para o preenchimento automático do lado do servidor:

Apps Script

// In your onConfig function:
var multiSelect1 =
  CardService.newSelectionInput()
    .setFieldName("value1")
    .setTitle("Server Autocomplete")
    .setType(CardService.SelectionInputType.MULTI_SELECT)
    .setMultiSelectMaxSelectedItems(3)
    .addDataSourceConfig(
      CardService.newDataSourceConfig()
        .setRemoteDataSource(
          CardService.newAction().setFunctionName('getAutocompleteResults')
        )
    )
    .addDataSourceConfig(
      CardService.newDataSourceConfig()
        .setPlatformDataSource(
          CardService.newPlatformDataSource()
            .setHostAppDataSource(
              CardService.newHostAppDataSource()
                .setWorkflowDataSource(
                  CardService.newWorkflowDataSource()
                    .setIncludeVariables(true)
                ))
        )
    );

// ... add widget to card ...

Processar a solicitação de preenchimento automático

A função especificada em setFunctionName (por exemplo, getAutocompleteResults) recebe um objeto de evento quando o usuário digita no campo. Essa função precisa:

  1. Verifique o event.workflow.elementUiAutocomplete.invokedFunction para garantir que ele corresponda ao nome da função esperada.
  2. Receba a entrada do usuário de event.workflow.elementUiAutocomplete.query.
  3. Consulte a fonte de dados externa usando a consulta.
  4. Retorne até 100 sugestões no formato necessário.

O exemplo a seguir mostra como implementar a função handleAutocompleteRequest() para retornar sugestões com base na consulta do usuário:

Apps Script

function handleAutocompleteRequest(event) {
  var invokedFunction = event.workflow.elementUiAutocomplete.invokedFunction;
  var query = event.workflow.elementUiAutocomplete.query;

  if (invokedFunction != "getAutocompleteResults" || query == undefined || query == "") {
    return {};
  }

  // Query your data source to get results based on the query
  let autocompleteResponse = AddOnsResponseService.newUpdateWidget()
    .addSuggestion(
      query + " option 1",
      query + "_option1",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 1 bottom text"
    )
    .addSuggestion(
      query + " option 2",
      query + "_option2",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 2 bottom text"
    ).addSuggestion(
      query + " option 3",
      query + "_option3",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 3 bottom text"
    );

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(
      AddOnsResponseService.newModifyCard()
        .setUpdateWidget(autocompleteResponse)
    );

  return AddOnsResponseService.newRenderActionBuilder()
    .setAction(modifyAction)
    .build();
}

// In your onConfig function, handle the autocomplete event
function onConfigAutocompleteTest(event) {
  // Handle autocomplete request
  if (event.workflow && event.workflow.elementUiAutocomplete) {
    return handleAutocompleteRequest(event);
  }

  // ... rest of your card building logic ...
}

Preenchimento automático de dados do Google Workspace

Você também pode preencher sugestões de preenchimento automático com dados do ambiente do Google Workspace do usuário:

  • Usuários do Google Workspace:preencha os usuários na mesma organização do Google Workspace.
  • Espaços do Google Chat:preenche os espaços do Google Chat de que o usuário é membro.

Para configurar isso, defina o PlatformDataSource no widget SelectionInput, especificando o WorkflowDataSourceType como USER ou SPACE.

Apps Script

// User Autocomplete
var multiSelect2 =
  CardService.newSelectionInput()
    .setFieldName("value2")
    .setTitle("User Autocomplete")
    .setType(CardService.SelectionInputType.MULTI_SELECT)
    .setMultiSelectMaxSelectedItems(3)
    .setPlatformDataSource(
      CardService.newPlatformDataSource()
        .setHostAppDataSource(
          CardService.newHostAppDataSource()
            .setWorkflowDataSource(
              CardService.newWorkflowDataSource()
                .setIncludeVariables(true)
                .setType(CardService.WorkflowDataSourceType.USER)
            ))
    );

// Chat Space Autocomplete
var multiSelect3 =
  CardService.newSelectionInput()
    .setFieldName("value3")
    .setTitle("Chat Space Autocomplete")
    .setType(CardService.SelectionInputType.MULTI_SELECT)
    .setMultiSelectMaxSelectedItems(3)
    .setPlatformDataSource(
      CardService.newPlatformDataSource()
        .setHostAppDataSource(
          CardService.newHostAppDataSource()
            .setWorkflowDataSource(
              CardService.newWorkflowDataSource()
                .setIncludeVariables(true)
                .setType(CardService.WorkflowDataSourceType.SPACE)
            ))
    );

Exemplo: combinar tipos de preenchimento automático

O exemplo a seguir mostra uma função onConfig que cria um card com três widgets SelectionInput e demonstra o preenchimento automático do servidor, do usuário e do espaço:

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Autocomplete Demo",
      "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "autocomplete_demo",
          "state": "ACTIVE",
          "name": "Autocomplete Demo",
          "description": "Provide autocompletion in input fields",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "A multi-select field with autocompletion",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfigAutocomplete",
            "onExecuteFunction": "onExecuteAutocomplete"
          }
        }
      ]
    }
  }
}

Apps Script

function onConfigAutocompleteTest(event) {
  // Handle autocomplete request
  if (event.workflow && event.workflow.elementUiAutocomplete) {
    return handleAutocompleteRequest(event);
  }

  // Server-side autocomplete widget
  var multiSelect1 =
    CardService.newSelectionInput()
      .setFieldName("value1")
      .setTitle("Server Autocomplete")
      .setType(CardService.SelectionInputType.MULTI_SELECT)
      .setMultiSelectMaxSelectedItems(3)
      .addDataSourceConfig(
        CardService.newDataSourceConfig()
          .setRemoteDataSource(
            CardService.newAction().setFunctionName('getAutocompleteResults')
          )
      )
      .addDataSourceConfig(
        CardService.newDataSourceConfig()
          .setPlatformDataSource(
            CardService.newPlatformDataSource()
              .setHostAppDataSource(
                CardService.newHostAppDataSource()
                  .setWorkflowDataSource(
                    CardService.newWorkflowDataSource()
                      .setIncludeVariables(true)
                  ))
          )
      );

  // User autocomplete widget
  var multiSelect2 =
    CardService.newSelectionInput()
      .setFieldName("value2")
      .setTitle("User Autocomplete")
      .setType(CardService.SelectionInputType.MULTI_SELECT)
      .setMultiSelectMaxSelectedItems(3)
      .setPlatformDataSource(
        CardService.newPlatformDataSource()
          .setHostAppDataSource(
            CardService.newHostAppDataSource()
              .setWorkflowDataSource(
                CardService.newWorkflowDataSource()
                  .setIncludeVariables(true)
                  .setType(CardService.WorkflowDataSourceType.USER)
              ))
      );

  // Space autocomplete widget
  var multiSelect3 =
    CardService.newSelectionInput()
      .setFieldName("value3")
      .setTitle("Chat Space Autocomplete")
      .setType(CardService.SelectionInputType.MULTI_SELECT)
      .setMultiSelectMaxSelectedItems(3)
      .setPlatformDataSource(
        CardService.newPlatformDataSource()
          .setHostAppDataSource(
            CardService.newHostAppDataSource()
              .setWorkflowDataSource(
                CardService.newWorkflowDataSource()
                  .setIncludeVariables(true)
                  .setType(CardService.WorkflowDataSourceType.SPACE)
              ))
      );

  var sectionBuilder =
    CardService.newCardSection()
      .addWidget(multiSelect1)
      .addWidget(multiSelect2)
      .addWidget(multiSelect3);

  var card =
    CardService.newCardBuilder()
      .addSection(sectionBuilder)
      .build();
  return card;
}

function handleAutocompleteRequest(event) {
  var invokedFunction = event.workflow.elementUiAutocomplete.invokedFunction;
  var query = event.workflow.elementUiAutocomplete.query;

  if (invokedFunction != "getAutocompleteResults" || query == undefined || query == "") {
    return {};
  }

  // Query your data source to get results
  let autocompleteResponse = AddOnsResponseService.newUpdateWidget()
    .addSuggestion(
      query + " option 1",
      query + "_option1",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 1 bottom text"
    )
    .addSuggestion(
      query + " option 2",
      query + "_option2",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 2 bottom text"
    ).addSuggestion(
      query + " option 3",
      query + "_option3",
      false,
      "https://developers.google.com/workspace/add-ons/images/person-icon.png",
      "option 3 bottom text"
    );

  const modifyAction = AddOnsResponseService.newAction()
    .addModifyCard(
      AddOnsResponseService.newModifyCard()
        .setUpdateWidget(autocompleteResponse)
    );

  return AddOnsResponseService.newRenderActionBuilder()
    .setAction(modifyAction)
    .build();
}

Personalizar botões do seletor de variáveis

É possível personalizar o botão do seletor de variáveis definindo o tamanho e o rótulo dele.

Tamanho do botão

Para definir o tamanho do botão, use setVariableButtonSize() com uma das seguintes enums VariableButtonSize:

  • UNSPECIFIED: o padrão. O botão é compacto no painel lateral e em tamanho normal em outros contextos.
  • COMPACT: o botão mostra apenas um sinal de adição (+).
  • FULL_SIZE: o botão mostra o rótulo de texto completo.

Rótulo do botão

Para definir o texto do botão, use setVariableButtonLabel().

Exemplo: personalização do seletor de variáveis

O exemplo a seguir mostra como configurar widgets TextInput com diferentes tamanhos de botão do seletor de variáveis e um rótulo personalizado.

  • Personalização do botão do seletor de variáveis na Web.
    Figura 1:personalização do botão de seleção de variáveis na Web.
  • Personalização do botão de seleção de variáveis em um painel lateral de complemento.
    Figura 2:personalização do botão de seleção de variáveis em um painel lateral do complemento.

Confira o arquivo de manifesto para personalizar os botões do seletor de variáveis:

JSON

{
  "timeZone": "America/Los_Angeles",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.locale"
  ],
  "addOns": {
    "common": {
      "name": "Variable button customization",
      "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "variable_picker_customization",
          "state": "ACTIVE",
          "name": "Variable Picker demo",
          "description": "List all possible variable picker customization options",
          "workflowAction": {
            "onConfigFunction": "onUpdateCardConfigFunction",
            "onExecuteFunction": "onUpdateCardExecuteFunction"
          }
        }
      ]
    }
  }
}

Confira o código para personalizar os botões do seletor de variáveis:

Apps Script

function onUpdateCardConfigFunction(event) {
  const textInput1 = CardService.newTextInput()
    .setFieldName("value1")
    .setTitle("Regular variable picker button")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.UNSPECIFIED)
      )
    );

  const textInput2 = CardService.newTextInput()
    .setFieldName("value2")
    .setTitle("Size: Unspecified")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.UNSPECIFIED)
      )
    );

  const textInput3 = CardService.newTextInput()
    .setFieldName("value3")
    .setTitle("Size: Full size")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.FULL_SIZE)
      )
    );

  const textInput4 = CardService.newTextInput()
    .setFieldName("value4")
    .setTitle("Size: Compact")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonSize(CardService.VariableButtonSize.COMPACT)
      )
    );

  const textInput5 = CardService.newTextInput()
    .setFieldName("value5")
    .setTitle("Custom button label")
    .setHostAppDataSource(
      CardService.newHostAppDataSource().setWorkflowDataSource(
        CardService.newWorkflowDataSource()
          .setIncludeVariables(true)
          .setVariableButtonLabel("New button label!")
      )
    );

  var cardSection = CardService.newCardSection()
    .addWidget(textInput1)
    .addWidget(textInput2)
    .addWidget(textInput3)
    .addWidget(textInput4)
    .addWidget(textInput5)
    .setId("section_1");

  var card = CardService.newCardBuilder().addSection(cardSection).build();

  return card;
}

function onUpdateCardExecuteFunction(event) {
}

Recursos específicos do Workspace Studio

Alguns widgets de card têm funcionalidades e recursos especiais específicos do Workspace Studio, detalhados aqui.

TextInput e SelectionInput

Os widgets TextInput e SelectionInput têm estes recursos específicos do Workspace Studio:

  • includeVariables: uma propriedade booleana que permite aos usuários selecionar variáveis de etapas anteriores. Para que o seletor de variáveis apareça nas etapas posteriores, o evento inicial e pelo menos uma variável de saída correspondente precisam ser mapeados para a variável.
  • type: um valor enumerado que preenche automaticamente as sugestões. Os valores aceitos incluem:
    • USER: oferece sugestões de preenchimento automático para pessoas nos contatos do usuário.
    • SPACE: oferece sugestões de preenchimento automático para espaços do Google Chat de que o usuário participa.

Quando includeVariables e type estão definidos, o campo de entrada combina as experiências deles. Os usuários podem selecionar uma variável do type correspondente em um menu suspenso e conferir sugestões de preenchimento automático.

  • Sugestões de preenchimento automático para um espaço do Google Chat.
    Figura 3:um usuário analisa as sugestões de preenchimento automático ao escolher um espaço.
  • No menu "Variáveis", os usuários podem selecionar variáveis de saída das etapas anteriores.
    Figura 4:um usuário seleciona a variável de saída de uma etapa anterior no menu suspenso ➕Variáveis.

Selecionar apenas uma variável de saída com um menu flutuante

É possível configurar um widget SelectionInput para que os usuários selecionem uma única variável de saída de uma etapa anterior usando um menu de estouro.

Quando você define SelectionInputType como OVERFLOW_MENU, o widget funciona como um seletor de variáveis dedicado. Ao contrário do uso de includeVariables com TextInput, que converte valores de variáveis em strings, o OVERFLOW_MENU preserva o tipo de dados original da variável selecionada.

Apps Script

const selectionInput = CardService.newSelectionInput()
  .setFieldName("variable_picker_1")
  .setTitle("Variable Picker")
  .setType(
    CardService.SelectionInputType.OVERFLOW_MENU
  );

Permitir que os usuários combinem texto e variáveis de saída

É possível configurar widgets TextInput para controlar como os usuários interagem com texto e variáveis de saída usando setInputMode().

  • RICH_TEXT: permite que os usuários combinem texto e variáveis de saída. O resultado é uma única string concatenada.
  • PLAIN_TEXT: restringe a entrada. Os usuários podem digitar texto ou selecionar uma única variável de saída. Selecionar uma variável substitui qualquer texto atual. Use esse modo para exigir tipos de dados específicos definidos no manifesto.

A imagem a seguir mostra dois widgets TextInput. O primeiro é configurado como RICH_TEXT e tem texto e uma variável de saída. O segundo é configurado como PLAIN_TEXT e permite apenas uma variável de saída.

  • Widgets de entrada de texto configurados como RICH_TEXT e PLAIN_TEXT
    Figura 5:widgets de entrada de texto configurados como RICH_TEXT e PLAIN_TEXT.

Recomendamos que você defina explicitamente o modo de entrada para todos os widgets TextInput.

Confira o arquivo de manifesto para configurar widgets TextInput com diferentes modos de entrada:

JSON

{
  "timeZone": "America/Toronto",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Text and output variable demo",
      "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "richTextDemo",
          "state": "ACTIVE",
          "name": "Rich Text Demo",
          "description": "Show the difference between rich text and plain text TextInput widgets",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "First user input",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              },
              {
                "id": "value2",
                "description": "Second user input",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfiguration",
            "onExecuteFunction": "onExecution"
          }
        }
      ]
    }
  }
}

Confira o código para configurar widgets TextInput com diferentes modos de entrada:

Apps Script

function onConfiguration() {
  const input1 = CardService.newTextInput()
    .setFieldName("value1")
    .setId("value1")
    .setTitle("Rich Text")
    .setHostAppDataSource(
      CardService.newHostAppDataSource()
        .setWorkflowDataSource(
          CardService.newWorkflowDataSource()
            .setIncludeVariables(true)
        )
    )
    // Set input mode to RICH_TEXT to allow mixed text and variables.
    .setInputMode(CardService.TextInputMode.RICH_TEXT);

  const input2 = CardService.newTextInput()
    .setFieldName("value2")
    .setId("value2")
    .setTitle("Plain text")
    .setHostAppDataSource(
      CardService.newHostAppDataSource()
        .setWorkflowDataSource(
          CardService.newWorkflowDataSource()
            .setIncludeVariables(true)
        )
    )
    // Set input mode to PLAIN_TEXT to enforce single variable selection.
    .setInputMode(CardService.TextInputMode.PLAIN_TEXT);

  const section = CardService.newCardSection()
    .addWidget(input1)
    .addWidget(input2);

  const card = CardService.newCardBuilder()
    .addSection(section)
    .build();

  return card;
}

function onExecution(e) {
}

Considerações e limitações do cartão

  • A navegação por cards, como popCard(), pushCard() e updateCard() não é compatível com complementos que estendem o Workspace Studio.

  • Quando SelectionInput é usado em um seletor de variáveis, os widgets só são compatíveis com "type": "MULTI_SELECT". Em outros cards de configuração, SelectionInput aceita todos os valores de SelectionType.