Issue with google workspace addon user event handling

This is a big of a doozy. I apologize….

I am building a google workspace add-on that allows you to:

  1. Select a file.
  2. Set a name for that file based on a bunch of user inputs.

I’ve run into a number of problems.

  1. One is that when I select the file, after it takes me through the authorization flow, it often gives me a "Content not available for this message" in the in the sidebar. I can’t figure out why it’s doing that. I am expecting it to just show the widgets with the various user input options.
  2. Another is that I can’t seem to record or log any of the user inputs. You can see my trying to invoke them as variables in the onSearch function and then write them to the file name.

Please let me know if you need more information to help trouble shoot. I’m sorry for the messiness of the code. This is a relatively new feature in google and I’ve basically just been mutating the code from example addons so there are some vestigial variables etc.

// See https://github.com/contributorpw/lodashgs
var _ = LodashGS.load();

/**
* Renders the home page for the add-on. Used in all host apps when
* no context selected.
*
* @param {Object} event - current add-on event
* @return {Card[]} Card(s) to display
*/
function onHomePage(event) {
  var card = buildSearchCard_();
  return [card];
}

/**
* Renders the contextual interface for a selected Drive file.
*
* @param {Object} event - current add-on event
* @return {Card[]} Card(s) to display
*/
function onDriveItemsSelected(event) {
  // For demo, only allow single select on files.
  if (event.drive.selectedItems.length != 1) {
    var message = "To set a file name, select one file only.";
    var card = buildSearchCard_(message);
    return [card];
  }

  var selectedItem = event.drive.selectedItems[0];
  if (!selectedItem.addonHasFileScopePermission) {
    // Need file access to read ACL, ask user to authorize.
    var authorizeFilesAction = CardService.newAction()
    .setFunctionName("onAuthorizeDriveFiles")
    .setLoadIndicator(CardService.LoadIndicator.SPINNER)
    .setParameters({id: selectedItem.id});
    var authorizationMessage = CardService.newTextParagraph()
    .setText("To change your file name, give permission to the tool to do so.");
    var authorizeButton = CardService.newTextButton()
    .setText("Authorize")
    .setOnClickAction(authorizeFilesAction);
    var card = CardService.newCardBuilder()
    .addSection(CardService.newCardSection()
                .addWidget(authorizationMessage)
                .addWidget(authorizeButton))
    .build();
    return [card];
  }}
/**
  // Have access, extract ACLs to find co-workers
  var emails = extractEmailsFromDrivePermissions_(event);
  var people = fetchPeople_(emails);
  if (people.length == 0) {
    var card = buildSearchCard_("");
    return [card];
  }
  var card = buildTeamListCard_(people)
  return [card];
}

/**
* Handles the click for requesting drive file access.
*
* @param {Object} event - current add-on event
* @return {ActionResponse} Request to authorize access to a drive item
*/
function onAuthorizeDriveFiles(event) {
  var id = event.parameters.id;
  return CardService.newDriveItemsSelectedActionResponseBuilder()
  .requestFileScope(id)
  .build();
}

/**
* Handles the user search request.
*
* @param {Object} event - current add-on event
* @return {Card[]} Card(s) to display
*/

function handleDateChange(event) {
  var dateTimeInput =
    event.commonEventObject.formInputs["myDateTimePickerWidgetID"];
  var hasDate = dateTimeInput.hasDate;

  // The following requires you to configure the add-on to read user locale
  // and timezone.
  // See https://developers.google.com/gsuite/add-ons/how-tos/access-user-locale
  var userTimezoneId = event.userTimezone.id;

  // Format and log the date-time selected using the user's timezone.
  var formattedDateTime;
  if (hasDate) {
    formattedDateTime = Utilities.formatDate(
      new Date(hasDate), userTimezoneId, "yyy/MM/dd hh:mm:ss");
  } else if (hasDate) {
    formattedDateTime = Utilities.formatDate(
      new Date(hasDate), userTimezoneId, "yyy/MM/dd")
      + ", Time unspecified";
  }

  if (formattedDateTime) {
    console.log(formattedDateTime);
  }
}

function onSearch(event) {
  if (!event.formInputs || !event.formInputs.query) {
    var notification = CardService.newNotification()
    .setText("Enter file name components");
    return CardService.newActionResponseBuilder()
    .setNotification(notification)
    .build();
  }
  var itemId = event.drive.selectedItems[0].id;
  var targetFile = DriveApp.getFileById(itemId)
 // var query =  event.formInputs.query[0];
  var dateOnlyPicker = 
event.commonEventObject.formInputs.dateOnlyPicker[""].stringInputs.value[0];
  var description = event.commonEventObject.formInputs.description[""].stringInputs.value[0];
  var department = event.commonEventObject.formInputs.department[""].stringInputs.value[0];


  targetFile.setName(dateOnlyPicker +"-"+ description +"-"+ department);
  Logger.log(dateOnlyPicker)
  Logger.log(description)
  Logger.log(department)
 // var people = queryPeople_(query);

}

/**


/**
* Builds the search interface for looking up people.
*
* @param {string} opt_error - Optional message to include (typically when
*    contextual search failed.)
* @return {Card} Card to display
*/
function buildSearchCard_(opt_error) {
  //var banner = CardService.newImage()
  //.setImageUrl('https://storage.googleapis.com/gweb-cloudblog-publish/original_images/Workforce_segmentation_1.png');

var dateOnlyPicker = CardService.newDatePicker()
    .setTitle("Enter the date.")
    .setFieldName("date_field")
    // Set default value as May 24 2019. Either a
    // number or string is acceptable.
    .setValueInMsSinceEpoch(1558668600000)
    .setOnChangeAction(CardService.newAction()
        .setFunctionName("handleDateChange"));
  
  var description = CardService.newTextInput()
   .setFieldName("description")
  .setHint("description")
  .setTitle("description");

  var department = CardService.newSelectionInput()
  .setType(CardService.SelectionInputType.DROPDOWN)
  .addItem("checkbox one title", "checkbox_one_value", false)
    .addItem("checkbox two title", "checkbox_two_value", true)
    .addItem("checkbox three title", "checkbox_three_value", true)
   .setFieldName("department")
  .setTitle("department");
  

  var onSubmitAction = CardService.newAction()
  .setFunctionName("onSearch")
  .setLoadIndicator(CardService.LoadIndicator.SPINNER);

  var submitButton = CardService.newTextButton()
  .setText("Set File Name")
  .setOnClickAction(onSubmitAction);

  var section = CardService.newCardSection()
 // .addWidget(banner)
 .addWidget(dateOnlyPicker)
  .addWidget(description)
  .addWidget(department)
  .addWidget(submitButton);

  if (opt_error) {
    var message = CardService.newTextParagraph()
    .setText("Note: " + opt_error);
    section.addWidget(message);
  }


  return CardService.newCardBuilder()
  .addSection(section)
  .build();
}

/**

Here’s the json manifest just so you can test it fully.

{
  "timeZone": "America/New_York",
  "dependencies": {
    "enabledAdvancedServices": [{
      "userSymbol": "Docs",
      "serviceId": "docs",
      "version": "v1"
    }, {
      "userSymbol": "Drive",
      "serviceId": "drive",
      "version": "v2"
    }, {
      "userSymbol": "Tasks",
      "serviceId": "tasks",
      "version": "v1"
    }, {
      "userSymbol": "People",
      "serviceId": "peopleapi",
      "version": "v1"
    }, {
      "userSymbol": "Slides",
      "serviceId": "slides",
      "version": "v1"
    }, {
      "userSymbol": "AdminDirectory",
      "serviceId": "admin",
      "version": "directory_v1"
    }, {
      "userSymbol": "AdminReports",
      "serviceId": "admin",
      "version": "reports_v1"
    }, {
      "userSymbol": "Gmail",
      "serviceId": "gmail",
      "version": "v1"
    }, {
      "userSymbol": "Sheets",
      "serviceId": "sheets",
      "version": "v4"
    }, {
      "userSymbol": "DriveActivity",
      "serviceId": "driveactivity",
      "version": "v2"
    }, {
      "userSymbol": "Calendar",
      "serviceId": "calendar",
      "version": "v3"
    }],
    "libraries": [{
      "userSymbol": "LodashGS",
      "libraryId": "1SQ0PlSMwndIuOAgtVJdjxsuXueECtY9OGejVDS37ckSVbMll73EXf2PW",
      "version": "5"
    }]
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes": ["https://www.googleapis.com/auth/script.locale","https://www.googleapis.com/auth/drive.readonly","https://www.googleapis.com/auth/drive","https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/admin.directory.user.readonly", "https://www.googleapis.com/auth/gmail.addons.execute", "https://www.googleapis.com/auth/gmail.addons.current.message.metadata", "https://www.googleapis.com/auth/calendar.addons.execute", "https://www.googleapis.com/auth/calendar.addons.current.event.read", "https://www.googleapis.com/auth/drive.addons.metadata.readonly", "https://www.googleapis.com/auth/drive.file"],
  "urlFetchWhitelist": [],
  "runtimeVersion": "DEPRECATED_ES5",
  "addOns": {
    "common": {
      "name": "Set Document Name",
      "logoUrl": "https://www.google.com/url?sa=i&url=https%3A%2F%2Fampion.net%2F&psig=AOvVaw28Hqpl6rsudxHTC24KN6Mu&ust=1612506227031000&source=images&cd=vfe&ved=0CAIQjRxqFwoTCOi9pfrLz-4CFQAAAAAdAAAAABAD",
      "layoutProperties": {
        "primaryColor": "#f24925",
        "secondaryColor": "#ea4335"
      },
      "homepageTrigger": {
        "runFunction": "onHomePage",
        "enabled": true
      },
      "universalActions": [{
        "label": "Feedback",
        "openLink": "https://github.com/googleworkspace/add-ons-samples/issues"
      }],
      "openLinkUrlPrefixes": ["https://github.com/googleworkspace/add-ons-samples/"]
    },
    "gmail": {
      "contextualTriggers": [{
        "unconditional": {
        },
        "onTriggerFunction": "onGmailMessageSelected"
      }]
    },
    "drive": {
      "homepageTrigger": {
        "runFunction": "onHomePage",
        "enabled": true
      },
      "onItemsSelectedTrigger": {
        "runFunction": "onDriveItemsSelected"
      }
    },
    "calendar": {
      "homepageTrigger": {
        "runFunction": "onHomePage",
        "enabled": true
      },
      "eventOpenTrigger": {
        "runFunction": "onCalendarEventOpen"
      },
      "currentEventAccess": "READ"
    }
  }
}

Here’s the log, per the first suggestion in first comment. I’m having some trouble deciphering it as well.

[21-02-04 14:44:15:004 EST] Starting execution
[21-02-04 14:44:15:154 EST] CardService.newDatePicker() [0 seconds]
[21-02-04 14:44:15:154 EST] CardService.DatePicker.setTitle([Enter the date.]) [0 seconds]
[21-02-04 14:44:15:154 EST] CardService.DatePicker.setFieldName([date_field]) [0 seconds]
[21-02-04 14:44:15:154 EST] CardService.DatePicker.setValueInMsSinceEpoch([1.5586686E12]) [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.newAction() [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.Action.setFunctionName([handleDateChange]) [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.DatePicker.setOnChangeAction([Action]) [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.newTextInput() [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.TextInput.setFieldName([description]) [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.TextInput.setHint([description]) [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.TextInput.setTitle([description]) [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.newSelectionInput() [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.SelectionInput.setType([DROPDOWN]) [0 seconds]
[21-02-04 14:44:15:155 EST] CardService.SelectionInput.addItem([checkbox one title, checkbox_one_value, false]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.SelectionInput.addItem([checkbox two title, checkbox_two_value, true]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.SelectionInput.addItem([checkbox three title, checkbox_three_value, true]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.SelectionInput.setFieldName([department]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.SelectionInput.setTitle([department]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.newAction() [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.Action.setFunctionName([onSearch]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.Action.setLoadIndicator([SPINNER]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.newTextButton() [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.TextButton.setText([Set File Name]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.TextButton.setOnClickAction([Action]) [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.newCardSection() [0 seconds]
[21-02-04 14:44:15:156 EST] CardService.CardSection.addWidget([DatePicker]) [0 seconds]
[21-02-04 14:44:15:157 EST] CardService.CardSection.addWidget([TextInput]) [0 seconds]
[21-02-04 14:44:15:157 EST] CardService.CardSection.addWidget([SelectionInput]) [0 seconds]
[21-02-04 14:44:15:157 EST] CardService.newCardBuilder() [0 seconds]
[21-02-04 14:44:15:157 EST] CardService.CardBuilder.addSection([CardSection]) [0 seconds]
[21-02-04 14:44:15:157 EST] CardService.CardBuilder.build() [0 seconds]
[21-02-04 14:44:15:159 EST] Execution succeeded [0.004 seconds total runtime]

16 thoughts on “Issue with google workspace addon user event handling”

  1. function loginCallback(e) {
      var userTimezoneId = e.userTimezone.id;
      var itemId = e.drive.selectedItems[0].id;
        var driveFile = DriveApp.getFileById(itemId); 
     var parentFolder = driveFile.getParents();
     while (parentFolder.hasNext()) {
       var folder = parentFolder.next();
       console.log(folder.getName());
      var targetFile = DriveApp.getFileById(itemId)
      var security_level = e.formInput.security_level
      var status = e.formInput.status
      var external_stakeholder = e.formInput.external_stakeholder
      var version = e.formInput.version
      var description = e.formInput.description
      var type = e.formInput.type
      var department = e.formInput.department
    
       var date_field_ms = (e.formInput.date_field.msSinceEpoch)+18000000;
       console.log(date_field_ms);
      var date_field = new Date(date_field_ms).toDateString()
        var formattedDateTime;
        formattedDateTime = Utilities.formatDate(
          new Date(date_field),"America/New_York", "yyyMMdd");
      var department = e.formInput.department
      console.log(description,date_field,department)
        targetFile.setName(formattedDateTime +"-"+security_level+"-"+type+"-"+description +"-"+ department+"-"+version+"-"+external_stakeholder+"-"+status);

    This fixed my problem for #2. Not minimal code, I know, but the scope of the project changed

    Reply

Leave a Comment