/***OpenacontactURL.*@param{Object}eaneventobject*@return{UniversalActionResponse}*/functionopenContactURL(e){//ActivatetemporaryGmailscopes,inthiscasesothatthe//openmessagemetadatacanberead.varaccessToken=e.gmail.accessToken;GmailApp.setCurrentMessageAccessToken(accessToken);//BuildURLtoopenbasedonabaseURLandthesender's email.//ThisURLmustbeincludedintheopenLinkUrlPrefixeswhitelist.varmessageId=e.gmail.messageId;varmessage=GmailApp.getMessageById(messageId);varsender=message.getFrom();varurl="https://www.example.com/urlbase/"+sender;returnCardService.newUniversalActionResponseBuilder().setOpenLink(CardService.newOpenLink().setUrl(url)).build();}/***Createacollectionofcardstocontroltheadd-onsettingsand*presentotherinformation.Thesecardsaredisplayedinalistwhen*theuserselectstheassociated"Open settings"universalaction.**@param{Object}eaneventobject*@return{UniversalActionResponse}*/functioncreateSettingsResponse(e){returnCardService.newUniversalActionResponseBuilder().displayAddOnCards([createSettingCard(),createAboutCard()]).build();}/***Createandreturnabuiltsettingscard.*@return{Card}*/functioncreateSettingCard(){returnCardService.newCardBuilder().setHeader(CardService.newCardHeader().setTitle('Settings')).addSection(CardService.newCardSection().addWidget(CardService.newSelectionInput().setType(CardService.SelectionInputType.CHECK_BOX).addItem("Ask before deleting contact","contact",false).addItem("Ask before deleting cache","cache",false).addItem("Preserve contact ID after deletion","contactId",false))//...continueaddingwidgetsorothersectionshere...).build();//Don't forget to build the card!}/***Createandreturnabuilt'About'informationalcard.*@return{Card}*/functioncreateAboutCard(){returnCardService.newCardBuilder().setHeader(CardService.newCardHeader().setTitle('About')).addSection(CardService.newCardSection().addWidget(CardService.newTextParagraph().setText('This add-on manages contact information. For more '+'details see the <a href="https://www.example.com/help">'+'help page</a>.'))//...addotherinformationwidgetsorsectionshere...).build();//Don't forget to build the card!}/***Runbackgroundtasks,noneofwhichshouldaltertheUI.*Alsorecordsthetimeofsyncinthescriptproperties.**@param{Object}eaneventobject*/functionrunBackgroundSync(e){varprops=PropertiesService.getUserProperties();props.setProperty("syncTime",newDate().toString());syncWithContacts();//Notshown.updateCache();//Notshown.validate();//Notshown.//noreturnvaluetellstheUItokeepshowingthecurrentcard.}
[null,null,["最后更新时间 (UTC):2024-12-22。"],[[["\u003cp\u003eUniversal actions are menu items that provide consistent access to specific functions like opening web pages, displaying UI cards, or running Apps Script functions, appearing on every card within a Google Workspace add-on.\u003c/p\u003e\n"],["\u003cp\u003eThese actions are defined in the add-on's manifest file and can be configured to either open a link directly or execute a specified Apps Script function when selected.\u003c/p\u003e\n"],["\u003cp\u003eWhen a universal action triggers a function, it can build and display UI cards, open a URL, or perform background tasks without altering the user interface.\u003c/p\u003e\n"],["\u003cp\u003eUniversal actions are beneficial for providing users with essential functionalities, like settings, help, or initiating workflows, regardless of their current location within the add-on.\u003c/p\u003e\n"]]],["Universal actions are menu items in add-ons that provide consistent functionality across all cards. Configured in the add-on's manifest, they allow users to open a web page, display UI cards, or run Apps Script functions. Each action is defined with menu text and either an `openLink` for web pages or a `runFunction` for script execution. The callback function in `runFunction` can build UI cards, open URLs, or run background tasks, all within a 30-second time limit.\n"],null,["# Universal actions are menu item elements that allow a user to open a new\nweb page, display new UI cards, or run a specific Apps Script function when\nselected. In operation they are very similar to\n[card actions](/workspace/add-ons/concepts/widgets#user_interaction_widgets),\nexcept that universal actions are always placed on every card in your add-on,\nregardless of the current add-on context.\n\nBy using universal actions, you can make sure the user always has access to\ncertain functionality, regardless of which part of your add-on they interact\nwith. Here are some example use cases for universal actions:\n\n- Open a settings web page (or display a settings card).\n- Show help information to the user.\n- Start a new workflow, such as 'Add new customer'.\n- Display a card that lets a user send feedback about the add-on.\n\nWhenever you have an action that does not depend on the current context,\nyou should consider making it a universal action.\n\nUsing universal actions\n-----------------------\n\nUniversal actions are configured in your add-on's project\n[manifest](/workspace/add-ons/concepts/workspace-manifests). Once you've configured a\nuniversal action, it is always available to users of your add-on. If the user\nis viewing a card, the set of universal actions you've defined always appears\nin the card menu, after any\n[card actions](/workspace/add-ons/concepts/widgets#user_interaction_widgets)\nyou've defined for that card. Universal actions appear in the card menus in the\nsame order in which they are defined in the add-on's manifest.\n\nConfiguring universal actions\n-----------------------------\n\nYou configure universal actions in your add-on's manifest; see\n[Manifests](/workspace/add-ons/concepts/workspace-manifests#manifest_structure_for_gmail_add-ons)\nfor more details.\n\nFor each action, you specify the text that should appear in the menu for that\naction. You can then specify an `openLink` field indicating that the action\nshould directly open a web page in a new tab. Alternatively, you can specify\na `runFunction` field that specifies an Apps Script callback function to\nexecute when the universal action is selected.\n\nWhen `runFunction` is used, the callback function specified usually does one\nof the following:\n\n- Builds UI cards to display immediately by returning a built [`UniversalActionResponse`](/apps-script/reference/card-service/universal-action-response) object.\n- Opens a URL, perhaps after doing other tasks, by returning a built `UniversalActionResponse` object.\n- Conducts background tasks that do not switch to a new card or open a URL. In this case the callback function returns nothing.\n\nWhen called, the callback function is passed an\n[event object](/workspace/add-ons/concepts/actions#action_event_objects)\ncontaining information about the open card and add-on context.\n| **Warning:** To keep the add-ons responsive, the [Card service](/apps-script/reference/card-service/card-service) limits universal action callback functions to a maximum of 30 seconds of execution time. If the execution takes longer than that, your add-on UI may not update its display properly.\n\nExample\n-------\n\nThe following code snippet shows an example manifest excerpt for a\nGoogle Workspace add-on that uses universal actions\nwhile extending Gmail. The code explicitly sets a metadata scope so that the\nadd-on can determine who sent the open message. \n\n \"oauthScopes\": [\n \"https://www.googleapis.com/auth/gmail.addons.current.message.metadata\"\n ],\n \"addOns\": {\n \"common\": {\n \"name\": \"Universal Actions Only Addon\",\n \"logoUrl\": \"https://www.example.com/hosted/images/2x/my-icon.png\",\n \"openLinkUrlPrefixes\": [\n \"https://www.google.com\",\n \"https://www.example.com/urlbase\"\n ],\n \"universalActions\": [{\n \"label\": \"Open google.com\",\n \"openLink\": \"https://www.google.com\"\n }, {\n \"label\": \"Open contact URL\",\n \"runFunction\": \"openContactURL\"\n }, {\n \"label\": \"Open settings\",\n \"runFunction\": \"createSettingsResponse\"\n }, {\n \"label\": \"Run background sync\",\n \"runFunction\": \"runBackgroundSync\"\n }],\n ...\n },\n \"gmail\": {\n \"contextualTriggers\": [\n {\n \"unconditional\": {},\n \"onTriggerFunction\": \"getContextualAddOn\"\n }\n ]\n },\n ...\n },\n ...\n\nThe three universal actions defined in preceding example do the following:\n\n- *Open google.com* opens \u003chttps://www.google.com\u003e in a new tab.\n- *Open contact URL* runs a function that determines what URL to open and then opens it in a new tab using an [`OpenLink`](/apps-script/reference/card-service/open-link) object. The code builds the URL using the sender's email address.\n- *Open settings* runs the `createSettingsCards()` function defined in the add-on script project. This function returns a valid [`UniversalActionResponse`](/apps-script/reference/card-service/universal-action-response) object containing a set of cards with add-on setting and other information. After the function finishes building this object, the UI displays the list of cards (see [Returning multiple cards](/workspace/add-ons/how-tos/navigation#returning_multiple_cards)).\n- *Run background sync* runs the `runBackgroundSync()` function defined in the add-on script project. This function does not build cards; instead it performs some other background tasks that do not change the UI. Since the function doesn't return a [`UniversalActionResponse`](/apps-script/reference/card-service/universal-action-response), the UI does not display a new card when the function finishes. Instead the UI displays a loading indicator spinner while the function is running.\n\nHere is an example of how you might construct the `openContactURL()`,\n`createSettingsResponse()`, and `runBackgroundSync()` functions: \n\n /**\n * Open a contact URL.\n * @param {Object} e an event object\n * @return {UniversalActionResponse}\n */\n function openContactURL(e) {\n // Activate temporary Gmail scopes, in this case so that the\n // open message metadata can be read.\n var accessToken = e.gmail.accessToken;\n GmailApp.setCurrentMessageAccessToken(accessToken);\n\n // Build URL to open based on a base URL and the sender's email.\n // This URL must be included in the openLinkUrlPrefixes whitelist.\n var messageId = e.gmail.messageId;\n var message = GmailApp.getMessageById(messageId);\n var sender = message.getFrom();\n var url = \"https://www.example.com/urlbase/\" + sender;\n return CardService.newUniversalActionResponseBuilder()\n .setOpenLink(CardService.newOpenLink()\n .setUrl(url))\n .build();\n }\n\n /**\n * Create a collection of cards to control the add-on settings and\n * present other information. These cards are displayed in a list when\n * the user selects the associated \"Open settings\" universal action.\n *\n * @param {Object} e an event object\n * @return {UniversalActionResponse}\n */\n function createSettingsResponse(e) {\n return CardService.newUniversalActionResponseBuilder()\n .displayAddOnCards(\n [createSettingCard(), createAboutCard()])\n .build();\n }\n\n /**\n * Create and return a built settings card.\n * @return {Card}\n */\n function createSettingCard() {\n return CardService.newCardBuilder()\n .setHeader(CardService.newCardHeader().setTitle('Settings'))\n .addSection(CardService.newCardSection()\n .addWidget(CardService.newSelectionInput()\n .setType(CardService.SelectionInputType.CHECK_BOX)\n .addItem(\"Ask before deleting contact\", \"contact\", false)\n .addItem(\"Ask before deleting cache\", \"cache\", false)\n .addItem(\"Preserve contact ID after deletion\", \"contactId\", false))\n // ... continue adding widgets or other sections here ...\n ).build(); // Don't forget to build the card!\n }\n\n /**\n * Create and return a built 'About' informational card.\n * @return {Card}\n */\n function createAboutCard() {\n return CardService.newCardBuilder()\n .setHeader(CardService.newCardHeader().setTitle('About'))\n .addSection(CardService.newCardSection()\n .addWidget(CardService.newTextParagraph()\n .setText('This add-on manages contact information. For more '\n + 'details see the \u003ca href=\"https://www.example.com/help\"\u003e'\n + 'help page\u003c/a\u003e.'))\n // ... add other information widgets or sections here ...\n ).build(); // Don't forget to build the card!\n }\n\n /**\n * Run background tasks, none of which should alter the UI.\n * Also records the time of sync in the script properties.\n *\n * @param {Object} e an event object\n */\n function runBackgroundSync(e) {\n var props = PropertiesService.getUserProperties();\n props.setProperty(\"syncTime\", new Date().toString());\n\n syncWithContacts(); // Not shown.\n updateCache(); // Not shown.\n validate(); // Not shown.\n\n // no return value tells the UI to keep showing the current card.\n }"]]