i am creating an appscript add-on using typescript and i am new with appscript but i am getting this error Error: Additional information input field not found
from what i understood the problem is that object e do not contain the values needed so the problem can be because of how the card is built or
onGenerateResponseButtonClick
function but i don’t know what i did wrong
/**
* Create a text button with specified text, action function, and parameters.
* @param {string} buttonText The text to display on the button.
* @param {string} functionName The name of the action function to call when the button is clicked.
* @param {Object} parameters The parameters to pass to the action function.
* @return {CardService.TextButton} The created text button.
*/
function createTextButton(buttonText, functionName, parameters) {
return CardService.newTextButton()
.setText(buttonText)
.setOnClickAction(CardService.newAction()
.setFunctionName(functionName)
.setParameters(parameters));
}
/**
* Retrieve plain text body of an email message.
* @param {string} messageId The ID of the email message.
* @return {string} The plain text body of the email message, or 'No content available' if not found.
*/
function getEmailPlainTextBody(messageId) {
try {
const message = GmailApp.getMessageById(messageId);
return message ? message.getPlainBody() : 'No content available';
} catch (error) {
Logger.log('Error fetching email body: ' + error);
return 'No content available';
}
}
/**
* Create a card header with specified title and subtitle.
* @param {string} title The title of the card header.
* @param {string} subtitle The subtitle of the card header.
* @return {CardService.CardHeader} The created card header.
*/
function createCardHeader(title, subtitle) {
return CardService.newCardHeader().setTitle(title).setSubtitle(subtitle);
}
/**
* Create a text input with specified properties.
* @param {string} fieldName The name of the text input field.
* @param {string} title The title of the text input.
* @param {string} hint The hint text for the text input.
* @param {string} value The initial value of the text input.
* @param {boolean} isMultiline Whether the text input should allow multiple lines.
* @return {CardService.TextInput} The created text input.
*/
function createTextInput(fieldName, title, hint, value, isMultiline = false) {
return CardService.newTextInput()
.setFieldName(fieldName)
.setTitle(title)
.setHint(hint)
.setValue(value)
.setMultiline(isMultiline);
}
/**
* Create a selection input with specified properties.
* @param {string} fieldName The name of the selection input field.
* @param {string} title The title of the selection input.
* @param {string[][]} items The items to populate the selection input.
* @return {CardService.SelectionInput} The created selection input.
*/
function createSelectionInput(fieldName, title, items) {
const selectionInput = CardService.newSelectionInput()
.setType(CardService.SelectionInputType.DROPDOWN)
.setTitle(title)
.setFieldName(fieldName);
items.forEach(item => {
selectionInput.addItem(item[0], item[1], item[2]);
});
return selectionInput;
}
/**
* Create a text paragraph with specified text.
* @param {string} text The text of the paragraph.
* @return {CardService.TextParagraph} The created text paragraph.
*/
function createTextParagraph(text) {
return CardService.newTextParagraph().setText(text);
}
/**
* Create a button set with specified buttons.
* @param {CardService.TextButton[]} buttons The buttons to include in the button set.
* @return {CardService.ButtonSet} The created button set.
*/
function createButtonSet(buttons) {
const buttonSet = CardService.newButtonSet();
buttons.forEach(button => {
buttonSet.addButton(button);
});
return buttonSet;
}
/**
* Create a card section with specified widgets.
* @param {CardService.Widget[]} widgets The widgets to include in the card section.
* @return {CardService.CardSection} The created card section.
*/
function createCardSection(widgets) {
const section = CardService.newCardSection();
widgets.forEach(widget => {
section.addWidget(widget);
});
return section;
}
/**
* Create a card builder with specified header and section.
* @param {CardService.CardHeader} header The header of the card.
* @param {CardService.CardSection} section The section of the card.
* @return {CardService.CardBuilder} The created card builder.
*/
function createCardBuilder(header, section) {
return CardService.newCardBuilder().setHeader(header).addSection(section);
}
/**
* Create a checkbox input with specified properties.
* @param {string} fieldName The name of the checkbox input field.
* @param {string} title The title of the checkbox.
* @param {boolean} isChecked Whether the checkbox is checked by default.
* @return {CardService.SelectionInput} The created checkbox input.
*/
function createCheckbox(fieldName, title, isChecked) {
return CardService.newSelectionInput()
.setType(CardService.SelectionInputType.CHECK_BOX)
.setFieldName(fieldName)
.addItem(title, title, isChecked);
}
/**
* Create response buttons with specified labels and action function.
* @param {string[]} labels The labels for the response buttons.
* @param {string} functionName The name of the action function to call when a button is clicked.
* @return {CardService.ButtonSet} The created button set.
*/
function createResponseButtons(labels, functionName) {
const buttons = labels.map(label => {
return CardService.newTextButton()
.setText(label)
.setOnClickAction(CardService.newAction()
.setFunctionName(functionName)
.setParameters({ response: label }));
});
return createButtonSet(buttons);
}
/**
* Create tone selection dropdown with specified options and action function.
* @param {string[]} options The options for the tone selection dropdown.
* @param {string} functionName The name of the action function to call when an option is selected.
* @return {CardService.SelectionInput} The created selection input.
*/
function createToneSelection(options, functionName) {
const items = options.map(option => [option, option.toLowerCase(), false]);
return createSelectionInput('tone_selection', 'Tone', items)
.setOnChangeAction(CardService.newAction().setFunctionName(functionName));
}
/**
* Callback for handling selection change in the tone selection dropdown.
* @param {Object} e The event object.
* @return {CardService.ActionResponse} The action response.
*/
function onSelectionChange(e) {
const selection = e.formInputs['tone_selection'];
// Here you can handle the selected option, but we won't rebuild the card
// Instead, let's update the response paragraph with the selected option
const updatedCard = CardService.newActionResponseBuilder()
.setStateChanged(true) // Indicate that card state changed
.setNotification(CardService.newNotification().setText('Tone selected: ' + selection))
.build();
return updatedCard;
}
/**
* Build a compose card with the given subject, sender, and body.
* @param {string} subject The subject of the email.
* @param {string} sender The sender of the email.
* @param {string} body The body of the email.
* @return {CardService.Card} The composed card.
*/
function buildComposeCard(subject, sender, body) {
Logger.log('Building compose card with subject: ' + subject + ', sender: ' + sender + ', body: ' + body);
// Ensure all parameters are strings to avoid setContent error
subject = subject || 'No Subject';
sender = sender || 'Unknown Sender';
body = body ? body.trim() : 'No content available'; // Trim whitespace from the body
// Create a button to generate a draft
const draftButton = CardService.newTextButton()
.setText('Generate Draft')
.setComposeAction(CardService.newAction()
.setFunctionName('composeAction'), CardService.ComposedEmailType.STANDALONE_DRAFT);
const card = CardService.newCardBuilder()
.setHeader(CardService.newCardHeader().setTitle('Compose Email'))
.addSection(CardService.newCardSection()
.addWidget(CardService.newTextParagraph().setText('Compose your email here.'))
.addWidget(CardService.newKeyValue().setTopLabel('Subject').setContent(subject))
.addWidget(CardService.newKeyValue().setTopLabel('From').setContent(sender))
.addWidget(draftButton) // Add the draft button to the card
.addWidget(CardService.newTextParagraph().setText(body)))
.build();
return card;
}
this si the helpers functions
/**
* Create a text button with specified text, action function, and parameters.
* @param {string} buttonText The text to display on the button.
* @param {string} functionName The name of the action function to call when the button is clicked.
* @param {Object} parameters The parameters to pass to the action function.
* @return {CardService.TextButton} The created text button.
*/
function createTextButton(buttonText, functionName, parameters) {
return CardService.newTextButton()
.setText(buttonText)
.setOnClickAction(CardService.newAction()
.setFunctionName(functionName)
.setParameters(parameters));
}
/**
* Retrieve plain text body of an email message.
* @param {string} messageId The ID of the email message.
* @return {string} The plain text body of the email message, or 'No content available' if not found.
*/
function getEmailPlainTextBody(messageId) {
try {
const message = GmailApp.getMessageById(messageId);
return message ? message.getPlainBody() : 'No content available';
} catch (error) {
Logger.log('Error fetching email body: ' + error);
return 'No content available';
}
}
/**
* Create a card header with specified title and subtitle.
* @param {string} title The title of the card header.
* @param {string} subtitle The subtitle of the card header.
* @return {CardService.CardHeader} The created card header.
*/
function createCardHeader(title, subtitle) {
return CardService.newCardHeader().setTitle(title).setSubtitle(subtitle);
}
/**
* Create a text input with specified properties.
* @param {string} fieldName The name of the text input field.
* @param {string} title The title of the text input.
* @param {string} hint The hint text for the text input.
* @param {string} value The initial value of the text input.
* @param {boolean} isMultiline Whether the text input should allow multiple lines.
* @return {CardService.TextInput} The created text input.
*/
function createTextInput(fieldName, title, hint, value, isMultiline = false) {
return CardService.newTextInput()
.setFieldName(fieldName)
.setTitle(title)
.setHint(hint)
.setValue(value)
.setMultiline(isMultiline);
}
/**
* Create a selection input with specified properties.
* @param {string} fieldName The name of the selection input field.
* @param {string} title The title of the selection input.
* @param {string[][]} items The items to populate the selection input.
* @return {CardService.SelectionInput} The created selection input.
*/
function createSelectionInput(fieldName, title, items) {
const selectionInput = CardService.newSelectionInput()
.setType(CardService.SelectionInputType.DROPDOWN)
.setTitle(title)
.setFieldName(fieldName);
items.forEach(item => {
selectionInput.addItem(item[0], item[1], item[2]);
});
return selectionInput;
}
/**
* Create a text paragraph with specified text.
* @param {string} text The text of the paragraph.
* @return {CardService.TextParagraph} The created text paragraph.
*/
function createTextParagraph(text) {
return CardService.newTextParagraph().setText(text);
}
/**
* Create a button set with specified buttons.
* @param {CardService.TextButton[]} buttons The buttons to include in the button set.
* @return {CardService.ButtonSet} The created button set.
*/
function createButtonSet(buttons) {
const buttonSet = CardService.newButtonSet();
buttons.forEach(button => {
buttonSet.addButton(button);
});
return buttonSet;
}
/**
* Create a card section with specified widgets.
* @param {CardService.Widget[]} widgets The widgets to include in the card section.
* @return {CardService.CardSection} The created card section.
*/
function createCardSection(widgets) {
const section = CardService.newCardSection();
widgets.forEach(widget => {
section.addWidget(widget);
});
return section;
}
/**
* Create a card builder with specified header and section.
* @param {CardService.CardHeader} header The header of the card.
* @param {CardService.CardSection} section The section of the card.
* @return {CardService.CardBuilder} The created card builder.
*/
function createCardBuilder(header, section) {
return CardService.newCardBuilder().setHeader(header).addSection(section);
}
/**
* Create a checkbox input with specified properties.
* @param {string} fieldName The name of the checkbox input field.
* @param {string} title The title of the checkbox.
* @param {boolean} isChecked Whether the checkbox is checked by default.
* @return {CardService.SelectionInput} The created checkbox input.
*/
function createCheckbox(fieldName, title, isChecked) {
return CardService.newSelectionInput()
.setType(CardService.SelectionInputType.CHECK_BOX)
.setFieldName(fieldName)
.addItem(title, title, isChecked);
}
/**
* Create response buttons with specified labels and action function.
* @param {string[]} labels The labels for the response buttons.
* @param {string} functionName The name of the action function to call when a button is clicked.
* @return {CardService.ButtonSet} The created button set.
*/
function createResponseButtons(labels, functionName) {
const buttons = labels.map(label => {
return CardService.newTextButton()
.setText(label)
.setOnClickAction(CardService.newAction()
.setFunctionName(functionName)
.setParameters({ response: label }));
});
return createButtonSet(buttons);
}
/**
* Create tone selection dropdown with specified options and action function.
* @param {string[]} options The options for the tone selection dropdown.
* @param {string} functionName The name of the action function to call when an option is selected.
* @return {CardService.SelectionInput} The created selection input.
*/
function createToneSelection(options, functionName) {
const items = options.map(option => [option, option.toLowerCase(), false]);
return createSelectionInput('tone_selection', 'Tone', items)
.setOnChangeAction(CardService.newAction().setFunctionName(functionName));
}
/**
* Callback for handling selection change in the tone selection dropdown.
* @param {Object} e The event object.
* @return {CardService.ActionResponse} The action response.
*/
function onSelectionChange(e) {
const selection = e.formInputs['tone_selection'];
// Here you can handle the selected option, but we won't rebuild the card
// Instead, let's update the response paragraph with the selected option
const updatedCard = CardService.newActionResponseBuilder()
.setStateChanged(true) // Indicate that card state changed
.setNotification(CardService.newNotification().setText('Tone selected: ' + selection))
.build();
return updatedCard;
}
/**
* Build a compose card with the given subject, sender, and body.
* @param {string} subject The subject of the email.
* @param {string} sender The sender of the email.
* @param {string} body The body of the email.
* @return {CardService.Card} The composed card.
*/
function buildComposeCard(subject, sender, body) {
Logger.log('Building compose card with subject: ' + subject + ', sender: ' + sender + ', body: ' + body);
// Ensure all parameters are strings to avoid setContent error
subject = subject || 'No Subject';
sender = sender || 'Unknown Sender';
body = body ? body.trim() : 'No content available'; // Trim whitespace from the body
// Create a button to generate a draft
const draftButton = CardService.newTextButton()
.setText('Generate Draft')
.setComposeAction(CardService.newAction()
.setFunctionName('composeAction'), CardService.ComposedEmailType.STANDALONE_DRAFT);
const card = CardService.newCardBuilder()
.setHeader(CardService.newCardHeader().setTitle('Compose Email'))
.addSection(CardService.newCardSection()
.addWidget(CardService.newTextParagraph().setText('Compose your email here.'))
.addWidget(CardService.newKeyValue().setTopLabel('Subject').setContent(subject))
.addWidget(CardService.newKeyValue().setTopLabel('From').setContent(sender))
.addWidget(draftButton) // Add the draft button to the card
.addWidget(CardService.newTextParagraph().setText(body)))
.build();
return card;
}
this si the debug for the card
Card: { toString: [Function],
setName: [Function],
build: [Function],
addCardAction: [Function],
setFixedFooter: [Function],
setDisplayStyle: [Function],
setPeekCardHeader: [Function],
addSection: [Function],
setHeader: [Function] }
hamed elghoul is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.