Este guia explica como atualizar dinamicamente um card de configuração em resposta a ações do usuário, como clicar em um botão ou selecionar um item em um menu.
Você pode inserir, remover ou substituir seções de cards e widgets para criar interfaces responsivas que se adaptam à entrada do usuário. Por exemplo, é possível atualizar uma interface de card para mostrar uma mensagem de erro de validação aos usuários que inserem uma string em um campo de entrada que espera um número inteiro e, em seguida, atualizar novamente para ocultar a mensagem depois que o usuário inserir um número inteiro.
Modificar seções e widgets de cards
Para atualizar um card, a ação do widget (como onClickAction) precisa chamar uma
função que retorne um objeto RenderActions com instruções de
modificação.
Nas seções de cards, é possível fazer as seguintes modificações:
- Inserir uma seção:adicione uma seção à parte de cima do card ou abaixo de uma seção
especificada por ID com
setInsertSection. - Remover uma seção:remova uma seção especificada por ID com
setRemoveSection. - Substituir uma seção:substitua uma seção atual por uma nova
especificada por ID com
setReplaceSection.
Nos widgets de card, é possível fazer as seguintes modificações:
- Inserir um widget:adicione um widget antes ou depois de um widget especificado por ID com
setInsertWidget. - Remover um widget:remova um widget especificado por ID com
setRemoveWidget. - Substituir um widget:substitua um widget atual por um novo com
setReplaceWidget.
Exemplo: inserir e remover seções e widgets
O exemplo a seguir cria um card de configuração com botões que chamam funções para modificar o card inserindo ou removendo widgets e seções.
JSON
{
"timeZone": "America/Los_Angeles",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"addOns": {
"common": {
"name": "Test Project",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",
"useLocaleFromApp": true
},
"flows": {
"workflowElements": [
{
"id": "modify_card",
"state": "ACTIVE",
"name": "Modify Card",
"workflowAction": {
"inputs": [
{
"id": "value1",
"description": "The first input",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
},
{
"id": "value2",
"description": "The second number",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
},
{
"id": "value3",
"description": "The third number",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
}
],
"outputs": [
{
"id": "result",
"description": "Modify Card result",
"cardinality": "SINGLE",
"dataType": {
"basicType": "STRING"
}
}
],
"onConfigFunction": "onConfig",
"onExecuteFunction": "onExecute"
}
}
]
}
}
}
Apps Script
// Return a configuration Card for the step.
function onConfig() {
const textInput_1 = CardService.newTextInput().setFieldName("value1").setTitle("First Value").setId("text_input_1").setHostAppDataSource(CardService.newHostAppDataSource().setWorkflowDataSource(CardService.newWorkflowDataSource().setIncludeVariables(true)));
const textInput_2 = CardService.newTextInput().setFieldName("value2").setTitle("Second Value").setId("text_input_2").setHostAppDataSource(CardService.newHostAppDataSource().setWorkflowDataSource(CardService.newWorkflowDataSource().setIncludeVariables(true)));
// Create buttons that call functions to modify the card.
const buttonSet = CardService.newButtonSet().setId("card_modification_buttons")
.addButton(
CardService.newTextButton()
.setAltText("Insert Card Section")
.setText("Insert Card Section")
.setOnClickAction(
CardService.newAction().setFunctionName('insertSection')
)
)
.addButton(
CardService.newTextButton()
.setAltText("Insert Text Widget")
.setText("Insert Text Widget")
.setOnClickAction(
CardService.newAction().setFunctionName('insertWidget')
)
);
var firstSection =
CardService.newCardSection()
.setId("card_section_1")
.addWidget(textInput_1)
.addWidget(textInput_2)
.addWidget(buttonSet);
var card = CardService.newCardBuilder()
.addSection(firstSection)
.build();
return card;
}
// If the step runs, return output variables.
function onExecute(event) {
var value1 = event.workflow.actionInvocation.inputs["value1"].stringValues[0];
var value2 = event.workflow.actionInvocation.inputs["value2"].stringValues[0];
var value3; // Declare value3
var result;
// Check if the "value3" key exists in the inputs, which only exists if
// the third text input is inserted to the Card.
if (event.workflow.actionInvocation.inputs["value3"]) {
value3 = event.workflow.actionInvocation.inputs["value3"].stringValues[0];
result = value1 + "\n" + value2 + "\n" + value3;
} else {
result = value1 + "\n" + value2;
}
// Output the file ID through a variableData, which can be used by
// later steps in a workflow.
const variableData = AddOnsResponseService.newVariableData().addStringValue(result);
let textFormatElement = AddOnsResponseService.newTextFormatElement().setText("Output: " + JSON.stringify(variableData));
let workflowTextFormat = AddOnsResponseService.newWorkflowTextFormat()
.addTextFormatElement(textFormatElement);
// The string key for each variableData must match with the IDs of the
// outputs defined in the manifest.
let returnAction = AddOnsResponseService.newReturnOutputVariablesAction()
.setVariables({ "result": variableData }).setLog(workflowTextFormat);
let hostAppAction = AddOnsResponseService.newHostAppAction().setWorkflowAction(returnAction);
const renderAction = AddOnsResponseService.newRenderActionBuilder()
.setHostAppAction(hostAppAction).build();
return renderAction;
}
/**
* Inserts a new CardSection with several widgets.
*/
function insertSection(event) {
console.log("event: " + JSON.stringify(event, null, 3));
const optionalSection = CardService.newCardSection().setId("card_section_2")
.addWidget(
CardService.newTextParagraph().setText("This is a text paragraph inside the new card section")
)
.addWidget(
CardService.newButtonSet().addButton(
CardService.newTextButton().setText("Remove Card Section").setOnClickAction(CardService.newAction().setFunctionName("removeSection"))))
.addWidget(
CardService.newButtonSet().addButton(
CardService.newTextButton().setText("Replace Card Section").setOnClickAction(CardService.newAction().setFunctionName("replaceSection"))));
// Insert the new section beneath section "card_section_1".
// You can also insert at the top of a Card.
const sectionInsertion = AddOnsResponseService.newInsertSection().insertBelowSection("card_section_1").setSection(optionalSection);
const modifyAction = AddOnsResponseService.newAction()
.addModifyCard(AddOnsResponseService.newModifyCard().setInsertSection(sectionInsertion));
return AddOnsResponseService.newRenderActionBuilder().setAction(modifyAction).build();
}
/**
* Replaces an existing CardSection with a new CardSection with the same ID.
*/
function replaceSection(event) {
console.log("event: " + JSON.stringify(event, null, 3));
const replacementSection = CardService.newCardSection().setId("card_section_2")
.addWidget(
CardService.newTextParagraph().setText("Card Section replaced!")
)
.addWidget(
CardService.newButtonSet().addButton(
CardService.newTextButton().setText("Remove Card Section").setOnClickAction(CardService.newAction().setFunctionName("removeSection"))));
const modifyAction = AddOnsResponseService.newAction()
.addModifyCard(AddOnsResponseService.newModifyCard().setReplaceSection(replacementSection));
return AddOnsResponseService.newRenderActionBuilder().setAction(modifyAction).build();
}
/**
* Replaces an existing CardWidget with a new CardWidget with the same ID.
*/
function replaceWidget(event) {
console.log("event: " + JSON.stringify(event, null, 3));
const replacementWidget = CardService.newTextParagraph().setText("This is a replacement widget!").setId("text_input_3");
const modifyAction = AddOnsResponseService.newAction()
.addModifyCard(AddOnsResponseService.newModifyCard().setReplaceWidget(replacementWidget));
return AddOnsResponseService.newRenderActionBuilder().setAction(modifyAction).build();
}
/**
* Inserts an additional text input widget and a button that can remove it.
*/
function insertWidget(event) {
console.log("event: " + JSON.stringify(event, null, 3));
const buttonSet = CardService.newButtonSet().setId("widget_1")
.addButton(
CardService.newTextButton()
.setAltText("Remove Widget")
.setText("Remove Widget")
.setOnClickAction(
CardService.newAction().setFunctionName('removeWidget')
))
.addButton(
CardService.newTextButton()
.setAltText("Replace Widget")
.setText("Replace Widget")
.setOnClickAction(
CardService.newAction().setFunctionName('replaceWidget')
));
const textInput_3 = CardService.newTextInput().setFieldName("value3").setTitle("Third Value").setId("text_input_3");
// Widgets can be inserted either before or after another widget.
// This example inserts a button below a text input, then inserts
// another text input between the existing text input and the new button.
const buttonSetInsertion = AddOnsResponseService.newInsertWidget().insertBelowWidget("text_input_2").setWidget(buttonSet);
const textInputInsertion = AddOnsResponseService.newInsertWidget().insertAboveWidget("widget_1").setWidget(textInput_3);
const modifyAction = AddOnsResponseService.newAction()
.addModifyCard(AddOnsResponseService.newModifyCard().setInsertWidget(buttonSetInsertion))
.addModifyCard(AddOnsResponseService.newModifyCard().setInsertWidget(textInputInsertion));
return AddOnsResponseService.newRenderActionBuilder().setAction(modifyAction).build();
}
/**
* Removes one or more existing widgets by ID.
*/
function removeWidget(event) {
console.log("event: " + JSON.stringify(event, null, 3));
const textInputDeletion = AddOnsResponseService.newRemoveWidget().setWidgetId("text_input_3");
const buttonSetDeletion = AddOnsResponseService.newRemoveWidget().setWidgetId("widget_1");
const modifyAction = AddOnsResponseService.newAction()
.addModifyCard(
AddOnsResponseService.newModifyCard().setRemoveWidget(textInputDeletion)
)
.addModifyCard(
AddOnsResponseService.newModifyCard().setRemoveWidget(buttonSetDeletion)
);
return AddOnsResponseService.newRenderActionBuilder().setAction(modifyAction).build();
}
/**
* Removes an existing card section by ID.
*/
function removeSection(event) {
console.log("event: " + JSON.stringify(event, null, 3));
const sectionDeletion = AddOnsResponseService.newRemoveSection().setSectionId('card_section_2');
const modifyAction = AddOnsResponseService.newAction()
.addModifyCard(
AddOnsResponseService.newModifyCard().setRemoveSection(sectionDeletion)
);
return AddOnsResponseService.newRenderActionBuilder().setAction(modifyAction).build();
}