Use [Action](https://developers.google.com/workspace/add-ons/concepts/actions) objects to build interactive
behavior into Google Workspace add-ons.

Action objects define what happens when a user interacts with a widget
(for example, a button) in the add-on UI.

## Add an action to a widget

To attach an action to a widget, use a
[widget handler function](https://developers.google.com/workspace/add-ons/concepts/actions#widget_handler_functions),
which also defines the condition that triggers the action. When triggered, the
action executes a designated
[callback function](https://developers.google.com/workspace/add-ons/concepts/actions#callback_functions).
The callback function is passed an
[event object](https://developers.google.com/workspace/add-ons/concepts/event-objects) that carries
information about the user's client-side interactions. You must implement the
callback function and have it return a specific response object.

### Example: Display a new card when a button is clicked

If you want to add a button to your add-on that builds
and displays a new card when clicked, follow these steps:

1. Create a button [widget](https://developers.google.com/workspace/add-ons/concepts/widgets#user_interaction_widgets).
2. To set a card-building action, add the button widget handler function [`setOnClickAction`](https://developers.google.com/apps-script/reference/card-service/text-button#setOnClickAction(Action)).
3. Create an Apps Script callback function to execute and specify it as the [`action`](https://developers.google.com/apps-script/reference/card-service/text-button#setOnClickAction(Action)) within the widget handler function. In this case, the callback function should build the card you want and return an [`ActionResponse`](https://developers.google.com/apps-script/reference/card-service/action-response) object. The response object tells the add-on to display the card the callback function built.

The following example shows the creation of a button widget. The action
requests the `drive.file` scope for the current file on behalf of the
add-on.

    /**
     * Adds a section to the Card Builder that displays a "REQUEST PERMISSION"
     * button. When it's clicked, the callback triggers file scope permission flow.
     * This is used in the add-on when the home-page displays basic data.
     */
    function addRequestFileScopeButtonToBuilder(cardBuilder) {
        var buttonSection = CardService.newCardSection();
        // If the add-on does not have access permission, add a button that
        // lets the user provide that permission on a per-file basis.
        var buttonAction = CardService.newAction()
          .setFunctionName("onRequestFileScopeButtonClickedInEditor");

        var button = CardService.newTextButton()
          .setText("Request permission")
          .setBackgroundColor("#4285f4")
          .setTextButtonStyle(CardService.TextButtonStyle.FILLED)
          .setOnClickAction(buttonAction);

        buttonSection.addWidget(button);
        cardBuilder.addSection(buttonSection);
    }

    /**
     * Callback function for a button action. Instructs Docs to display a
     * permissions dialog to the user, requesting `drive.file` scope for the 
     * current file on behalf of this add-on.
     *
     * @param {Object} e The parameters object that contains the document's ID
     * @return {editorFileScopeActionResponse}
     */
    function onRequestFileScopeButtonClickedInEditor(e) {
      return CardService.newEditorFileScopeActionResponseBuilder()
          .requestFileScopeForActiveDocument().build();
    }

## File access interactions for REST APIs

Google Workspace add-ons that extend the Editors and use REST APIs can include an
additional widget action to request file access. This action requires the
associated action callback function to return a specialized response object:

| Action attempted | Callback function should return |
|---|---|
| [Request file access](https://developers.google.com/workspace/add-ons/editors/gsao/editor-actions#request_file_access_for_current_document) | `EditorFileScopeActionResponse` |

To make use of this widget action and response object, all of the following
must be true:

- The add-on uses REST APIs.
- The add-on presents the request file scope dialog using the `CardService.newEditorFileScopeActionResponseBuilder().requestFileScopeForActiveDocument().build();` method.
- The add-on includes the `https://www.googleapis.com/auth/drive.file` editor scope and `onFileScopeGranted` trigger in its manifest.

### Request file access for current document

To request file access for the current document, follow these steps:

1. Build a homepage card that checks whether the add-on has `drive.file` scope.
2. For cases where the add-on hasn't been granted `drive.file` scope, build a way to request that users grant `drive.file` scope for the current document.

#### Example: Get current document access in Docs

The following example builds an interface for Docs that displays
the size of the current document. If the add-on doesn't
have `drive.file` authorization, it displays a button to initiate the file
scope authorization.

    /**
     * Build a card that checks selected items' quota usage. Checking
     * quota usage requires user-permissions, so this add-on provides a button
     * to request `drive.file` scope for items the add-on doesn't yet have
     * permission to access.
     *
     * @param e The event object passed containing information about the
     *   current document.
     * @return {Card}
     */
    function onDocsHomepage(e) {
      return createAddOnView(e);
    }

    function onFileScopeGranted(e) {
      return createAddOnView(e);
    }

    /**
     * For the current document, display either its quota information or
     * a button that lets the user provide permission to access that
     * file to retrieve its quota details.
     *
     * @param e The event containing information about the current document
     * @return {Card}
     */
    function createAddOnView(e) {
      var docsEventObject = e['docs'];
      var builder =  CardService.newCardBuilder();

      var cardSection = CardService.newCardSection();
      if (docsEventObject['addonHasFileScopePermission']) {
        cardSection.setHeader(docsEventObject['title']);
        // This add-on uses the recommended, limited-permission `drive.file`
        // scope to get granular per-file access permissions.
        // See: https://developers.google.com/drive/api/v2/about-auth
        // If the add-on has access permission, read and display its quota.
        cardSection.addWidget(
          CardService.newTextParagraph().setText(
              "This file takes up: " +
              getQuotaBytesUsed(docsEventObject['id'])));
      } else {
        // If the add-on does not have access permission, add a button that
        // lets the user provide that permission on a per-file basis.
        cardSection.addWidget(
          CardService.newTextParagraph().setText(
              "The add-on needs permission to access this file's quota."));

        var buttonAction = CardService.newAction()
          .setFunctionName("onRequestFileScopeButtonClicked");

        var button = CardService.newTextButton()
          .setText("Request permission")
          .setOnClickAction(buttonAction);

        cardSection.addWidget(button);
      }
      return builder.addSection(cardSection).build();
    }

    /**
     * Callback function for a button action. Instructs Docs to
     * display a permissions dialog to the user, requesting `drive.file` scope for
     * the current file on behalf of this add-on.
     *
     * @param {Object} e The parameters object that contains the document's ID
     * @return {editorFileScopeActionResponse}
     */
    function onRequestFileScopeButtonClicked(e) {
      return CardService.newEditorFileScopeActionResponseBuilder()
          .requestFileScopeForActiveDocument().build();
    }