Author Archives: Google Apps Developer Blog Editor

Make progress (bars) in presentations with Slides Add-ons



We recently introduced Google Slides Add-ons so developers can add functionality from their apps to ours. Here are examples of Slides Add-ons that some of our partners have already built—remember, you can also add functionality to other apps outside of Slides, like Docs, Sheets, Gmail and more.

When it comes to Slides, if your users are delivering a presentation or watching one, sometimes it's good to know how far along you are in the deck. Wouldn't it be great if Slides featured progress bars?
In the latest episode of the G Suite Dev Show, G Suite engineer Grant Timmerman and I show you how to do exactly that—implement simple progress bars using a Slides Add-on.

Using Google Apps Script, we craft this add-on which lets users turn on or hide progress bars in their presentations. The progress bars are represented as appropriately-sized rectangles at the bottom of slide pages. Here's a snippet of code for createBars(), which adds the rectangle for each slide.

var BAR_ID = 'PROGRESS_BAR_ID';
var BAR_HEIGHT = 10; // px
var presentation = SlidesApp.getActivePresentation();

function createBars() {
var slides = presentation.getSlides();
deleteBars();
for (var i = 0; i < slides.length; ++i) {
var ratioComplete = (i / (slides.length - 1));
var x = 0;
var y = presentation.getPageHeight() - BAR_HEIGHT;
var barWidth = presentation.getPageWidth() * ratioComplete;
if (barWidth > 0) {
var bar = slides[i].insertShape(SlidesApp.ShapeType.RECTANGLE,
x, y, barWidth, BAR_HEIGHT);
bar.getBorder().setTransparent();
bar.setLinkUrl(BAR_ID);
}
}
}

To learn more about this sample and see all of the code, check out the Google Slides Add-on Quickstart. This is just one example of what you can build using Apps Script and add-ons; here’s another example where you can create a slide presentation from a collection of images using a Slides Add-on.

If you want to learn more about Apps Script, check out the video library or view more examples of programmatically accessing Google Slides here. To learn about using Apps Script to create other add-ons, check out this page in the docs.

Develop bot integrations with the Hangouts Chat platform and API



You might have seen that we announced new features in G Suite to help teams transform how they work, including Hangouts Chat, a new messaging platform for enterprise collaboration on web and mobile. Perhaps more interesting is that starting today you’ll be able to craft your own bot integrations using the Hangouts Chat developer platform and API.

Now, you can create bots to streamline work—automate manual tasks or give your users new ways to connect with your application, all with commands issued from chat rooms or direct messages (DMs). Here are some ideas you might consider:
  • Create a bot that can complete simple tasks or query for information 
  • Create a bot that can post asynchronous notifications in any room or DM 
  • Use interactive UI cards to bring your message responses to life 
  • Use Google Apps Script to create custom bots for your colleagues or organization 
For example, a bot can take a location from a user, look it up using the Google Maps API, and display the resulting map right within the same message thread in Hangouts Chat. The bot output you see in the image below is generated from the Apps Script bot integration. It returns the JSON payload just below the same image shown on this page in the documentation.


When messages are sent to an Apps Script bot, the onMessage() function is called and passed an event object. The code below extracts the bot name as well as the location requested by the user. The location is then passed to Google Maps to create the static map as well as an openLink URL that takes the user directly to Google Maps if either the map or "Open in Google Maps" link is clicked.

function onMessage(e) {
var bot = e.message.annotations[0].userMention.user.displayName;
var loc = encodeURI(e.message.text.substring(bot.length+2));
var mapClick = {
"openLink": {
"url": "https://google.com/maps/search/?api=1&query=" + loc
}
};

return {
// see JSON payload in the documentation link above
};
}

Finally, this function returns everything Hangouts Chat needs to render a UI card assuming the appropriate links, data and Google Maps API key were added to the response JSON payload. It may be surprising, but this is the entire bot and follows this common formula: get the user request, collate the results and respond back to the user.

When results are returned immediately like this, it's known as a synchronous bot. Using the API isn't necessary because you're just responding to the HTTP request. If your bot requires additional processing time or must execute a workflow out-of-band, return immediately then post an asynchronous response when the background jobs have completed with data to return. Learn more about bot implementation, its workflow, as well as synchronous vs. asynchronous responses.

Developers are not constrained to using Apps Script, although it is perhaps one of the easiest ways to create and deploy bots. Overall, you can write and host bots on a variety of platforms:
No longer are chat rooms just for conversations. With feature-rich, intelligent bots, users can automate tasks, get critical information or do other heavy-lifting with a simple message. We're excited at the possibilities that await both developers and G Suite users on the new Hangouts Chat platform and API.

Introducing the Gmail Developer Preview of AMP in Email


You may have heard of the open-source framework, Accelerated Mobile Pages (AMP). It’s a framework for developers to create faster-loading mobile content on the web. Beyond simply loading pages faster, AMP now supports building a wide range of rich pages for the web. Today, we’re announcing AMP for Email so that emails can be formatted and sent as AMP documents. As a part of this, we’re also kicking off the Gmail Developer Preview of AMP for Email—so once you’ve built your emails, you’ll be able to test them in Gmail.

AMP for Email opens up several new possibilities:
  • Design interactive components for email using a large library of supported AMP components like amp-carousel, amp-form, amp-bind, amp-list and more
  • Help your content stay up-to-date and interactive for your users.
  • Create more engaging and actionable email experiences
Here’s an example:
Brows and save your favorite items in Pinterest


<!doctype html>
<html ⚡4email>
<head>
<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js">&lt'/script>
<!-- The AMP4email boilerplate. -->
<style amp4email-boilerplate>body{visibility:hidden}</style>
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<script async custom-element="amp-selector" src="https://cdn.ampproject.org/v0/amp-selector-0.1.js"></script>
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
<script async custom-element="amp-form" src="https://cdn.ampproject.org/v0/amp-form-0.1.js"></script>
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.1.js"></script>
<style amp-custom> html{font-family: 'Roboto';}
...
</style>
</head>
<body>
<h2>Hello dear user,</h2>
<div class="photo-gallery">
<div class="text">Photos from your latest trips:
<span [text]="+selectedSlide + 1">1</span>/4</div>
<amp-selector layout="container" name="carousel-selector"...>
<amp-carousel controls width="430" height="80">
<amp-img ...></amp-img>
...
</amp-carousel>
</amp-selector>
<amp-carousel ...>
<amp-img ...></amp-img>
...
</amp-carousel>
<div class="trip-location">Please rate your trip location:</div>
<form id="rating" class="p2" method="post" ...>
<fieldset class="rating">
<input name="rating" type="radio" id="rating1" value="1" .../>
<label for="rating1" title="1 stars">★</label>
...
</fieldset>
<div submit-success>
<template type="amp-mustache">
<div class="text">Thanks for rating {{rating}} star(s)!</div>
</template>
</div>
</form>
</div>
</body>
</html>
[Full example in AmpByExample’s Playground]

The AMP for Email spec is available today and will be supported in Gmail later this year. To get preview access to how Gmail will support AMP for Email, sign up here. Since it’s an open spec, we look forward to seeing other email clients adopt it, too.

Publish Gmail Add-ons to your domain


We extended the Gmail Add-on preview toward the end of last year, so that developers can bring the functionality of business apps they rely on directly into Gmail. Now, we’re also making it easier for you to develop and publish Gmail Add-ons domain-wide. Create add-ons for users to access tools directly in their inbox, like your company directory, HR tools or other CRM solutions.

You can now:
  • Publish Gmail Add-ons to users in your G Suite domain. This lets you build and deploy custom add-ons for workflows or processes that are unique to your company.
  • Install Gmail Add-ons for G Suite accounts before they’re published. This way, you can test your add-on before releasing widely in the workplace.
  • Plus, G Suite admins can install add-ons for their domains. This helps G Suite users perform domain-wide installs for any add-on you build, so more people have the chance to try your add-on (or experiment with add-ons domain-wide).
Check out this video to see what it’s like to build an add-on then start building it yourself with this hands-on codelab. You can also view already-built add-ons in the G Suite Marketplace. Or, if you have another project in mind, submit your add-on idea for consideration.

We’re on a mission to make work easier and a big part of that means giving you the tools you need to speed up workflows. Build on!

3 new tools to help improve your Apps Script development and management experience



Apps Script has come a long way since we first launched scripting with Google Sheets. Now, Apps Script supports more than 5 million weekly active scripts that are integrated with a host of G Suite apps, and more than 1 billion daily executions.

As developers increasingly rely on Apps Script for mission-critical enterprise applications, we've redoubled our efforts to improve its power, reliability and operational monitoring, like our recently announced integration with Stackdriver for logging and error reporting. Today, we’re providing three new tools to help further improve your workflows and manage Apps Script projects:

  1. Apps Script dashboard, to help you manage, debug and monitor all of your projects in one place. 
  2. Apps Script API, so you can programmatically manage Apps Script source files, versions and deployments. 
  3. Apps Script Command Line Interface, for easy access to Apps Script API functionality from your terminal and shell scripts. 

Apps Script dashboard 

Over the next few weeks we’ll be making a new dashboard available to help you manage, debug and monitor all of your Apps Script projects from one place.
In this new dashboard—available at script.google.com—you will be able to:
  • View and search all of your projects. 
  • Monitor the health and usage of projects you care about. 
  • View details about individual projects. 
  • View a log of project executions and terminate long-running executions. 
Check out the documentation for more detail on the dashboard. If you encounter any issues, please use the feedback link in the left column of the new dashboard or file a bug.

Apps Script API 

The new Apps Script dashboard is built on top of a powerful new Apps Script API which replaces and extends the Execution API. This new Apps Script API provides a RESTful interface for developers to create, manage, deploy and execute their scripts from their preferred programming language. This gives you control to create development workflows and deployment strategies that fit your needs. With this new API, you can:
  • Create, read, update and delete script projects, source files and versions. 
  • Manage project deployments and entry points (web app, add-on, execution). 
  • Obtain project execution metrics and process data. 
  • Run script functions. 
To learn more about the new Apps Script API, check out the documentation. If you encounter any issues please ask a question on Stack Overflow or file a bug.

Apps Script Command Line Interface 

Lastly, we’re pleased to introduce the first open-source client of the Apps Script API, a command-line interface tool called clasp (Command Line Apps Script Projects). clasp allows you to access the management functionality of the Apps Script API with intuitive terminal commands and is available as an open-source project on GitHub.
clasp allows developers to create, pull and push Apps Script projects, plus manage deployments and versions with terminal commands and shell scripts. clasp also allows you to write and maintain your Apps Script projects using the development tools of your choice including your native IDE, Git and GitHub.

To get started, try the clasp codelab. You can file issues or ask questions on the clasp project GitHub page.

We’re doubling down on powerful platforms like Apps Script. We hope these new additions help ease your development process.

Hangouts Meet now available in the Google Calendar API



Thousands of developers use Google Calendar API to read, create and modify Google Calendar events, and quite often, these events represent meetings happening not just face-to-face but also remotely. We introduced Hangouts Meet earlier this year to give users richer conference experiences, adding video call links and phone numbers for G Suite Enterprise. Starting today, we are making it possible to access all that conference information through the Google Calendar API. With this update, developers can now:
  • Read conference data associated with events 
  • Copy conference data from one event to another 
  • Request new conference generation for an event 
The API supports all Hangouts versions.

Reading conference data 

Conference information is stored in a new event attribute called conferenceData. conferenceData provides information about the solution that was used to create the conference (such as Hangouts Meet) and a set of entry points (like a video call link and phone number). Everything the user needs to know to join a conference call is there.

To help you build even better user experiences, we also give you access to icons and user-readable labels that you can use in your products. In JSON format, conferenceData looks something like this (of course, your actual meeting IDs and phone numbers will vary):
"conferenceData": {
"entryPoints": [
{
"entryPointType": "video",
"uri": "https://meet.google.com/wix-pvpt-njj",
"label": "meet.google.com/wix-pvpt-njj"
},
{
"entryPointType": "more",
"uri": "https://tel.meet/wix-pvpt-njj?pin=1701789652855",
"pin": "1701789652855"
},
{
"entryPointType": "phone",
"uri": "tel:+44-20-3873-7654",
"label": "+44 20 3873 7654",
"pin": "6054226"
}
],
"conferenceSolution": {
"key": {
"type": "hangoutsMeet"
},
"name": "Hangouts Meet",
"iconUri": "https://lh5.googleusercontent.com/proxy/bWvYBOb7O03a7HK5iKNEAPoUNPEXH1CHZjuOkiqxHx8OtyVn9sZ6Ktl8hfqBNQUUbCDg6T2unnsHx7RSkCyhrKgHcdoosAW8POQJm_ZEvZU9ZfAE7mZIBGr_tDlF8Z_rSzXcjTffVXg3M46v"
},
"conferenceId": "wix-pvpt-njj",
"signature": "ADwwud9tLfjGQPpT7bdP8f3bq3DS"
}

And this, for example, is how you would retrieve and display conference solution name and icon:
var solution = event.conferenceData.conferenceSolution;

var content = document.getElementById("content");
var text = document.createTextNode("Join " + solution.name);
var icon = document.createElement("img");
icon.src = solution.iconUri;

content.appendChild(icon);
content.appendChild(text);
The result of the code above will look like this in the user interface:

Copying conferences across events 

Sometimes displaying information is not enough—you might want to update it as well. This is especially true when scheduling multiple Calendar events with the same conference details. Say you’re developing a recruiting application that sets up separate events for the candidate and the interviewer; you want to protect the interviewer’s identity, but you also want to make sure all participants join the same conference call. To do this, you can now copy conference information from one event to another by simply writing to conferenceData.

To ensure that only existing Hangouts conferences are copied, and to help safeguard your users against malicious actors, copied conference data will always be verified by the Google Calendar API using the signature field, so don’t forget to copy it too.

Creating a new conference for an event 

Finally, the API allows developers to request conference creation. Simply provide a conferenceData.createRequest and set the conferenceDataVersion request parameter to 1 when creating or updating events. Conferences are created asynchronously, but you can always check the status of your request to let your users know what’s happening. For example, to request conference generation for an existing event (again, your request and event IDs will be different):
var eventPatch = {
conferenceData: {
createRequest: {requestId: "7qxalsvy0e"}
}
};

gapi.client.calendar.events.patch({
calendarId: "primary",
eventId: "7cbh8rpc10lrc0ckih9tafss99",
resource: eventPatch,
sendNotifications: true,
conferenceDataVersion: 1
}).execute(function(event) {
console.log("Conference created for event: %s", event.htmlLink);
});
The immediate response to this call might not yet contain the fully-populated conferenceData which is indicated by status pending:
"conferenceData": {
"createRequest": {
"requestId": "7qxalsvy0e",
"conferenceSolutionKey": {
"type": "hangoutsMeet"
},
"status": {
"statusCode": "pending"
}
}
}
Once the statusCode changes to success, the conference information is populated. Finally, if you are developing a Google Calendar client, you might also want to know beforehand which of the three Hangouts solutions (consumer Hangouts, classic Hangouts and Hangouts Meet) will be used to create the conference. You can get that information by checking allowedConferenceSolutionTypes in a calendar’s conferenceProperties.

To get started, check out the documentation page for managing conference data. We can’t wait to see what you build with these new features in the Google Calendar API.

Hangouts Meet now available in the Google Calendar API



Thousands of developers use Google Calendar API to read, create and modify Google Calendar events, and quite often, these events represent meetings happening not just face-to-face but also remotely. We introduced Hangouts Meet earlier this year to give users richer conference experiences, adding video call links and phone numbers for G Suite Enterprise. Starting today, we are making it possible to access all that conference information through the Google Calendar API. With this update, developers can now:
  • Read conference data associated with events 
  • Copy conference data from one event to another 
  • Request new conference generation for an event 
The API supports all Hangouts versions.

Reading conference data 

Conference information is stored in a new event attribute called conferenceData. conferenceData provides information about the solution that was used to create the conference (such as Hangouts Meet) and a set of entry points (like a video call link and phone number). Everything the user needs to know to join a conference call is there.

To help you build even better user experiences, we also give you access to icons and user-readable labels that you can use in your products. In JSON format, conferenceData looks something like this (of course, your actual meeting IDs and phone numbers will vary):
"conferenceData": {
"entryPoints": [
{
"entryPointType": "video",
"uri": "https://meet.google.com/wix-pvpt-njj",
"label": "meet.google.com/wix-pvpt-njj"
},
{
"entryPointType": "more",
"uri": "https://tel.meet/wix-pvpt-njj?pin=1701789652855",
"pin": "1701789652855"
},
{
"entryPointType": "phone",
"uri": "tel:+44-20-3873-7654",
"label": "+44 20 3873 7654",
"pin": "6054226"
}
],
"conferenceSolution": {
"key": {
"type": "hangoutsMeet"
},
"name": "Hangouts Meet",
"iconUri": "https://lh5.googleusercontent.com/proxy/bWvYBOb7O03a7HK5iKNEAPoUNPEXH1CHZjuOkiqxHx8OtyVn9sZ6Ktl8hfqBNQUUbCDg6T2unnsHx7RSkCyhrKgHcdoosAW8POQJm_ZEvZU9ZfAE7mZIBGr_tDlF8Z_rSzXcjTffVXg3M46v"
},
"conferenceId": "wix-pvpt-njj",
"signature": "ADwwud9tLfjGQPpT7bdP8f3bq3DS"
}

And this, for example, is how you would retrieve and display conference solution name and icon:
var solution = event.conferenceData.conferenceSolution;

var content = document.getElementById("content");
var text = document.createTextNode("Join " + solution.name);
var icon = document.createElement("img");
icon.src = solution.iconUri;

content.appendChild(icon);
content.appendChild(text);
The result of the code above will look like this in the user interface:

Copying conferences across events 

Sometimes displaying information is not enough—you might want to update it as well. This is especially true when scheduling multiple Calendar events with the same conference details. Say you’re developing a recruiting application that sets up separate events for the candidate and the interviewer; you want to protect the interviewer’s identity, but you also want to make sure all participants join the same conference call. To do this, you can now copy conference information from one event to another by simply writing to conferenceData.

To ensure that only existing Hangouts conferences are copied, and to help safeguard your users against malicious actors, copied conference data will always be verified by the Google Calendar API using the signature field, so don’t forget to copy it too.

Creating a new conference for an event 

Finally, the API allows developers to request conference creation. Simply provide a conferenceData.createRequest and set the conferenceDataVersion request parameter to 1 when creating or updating events. Conferences are created asynchronously, but you can always check the status of your request to let your users know what’s happening. For example, to request conference generation for an existing event (again, your request and event IDs will be different):
var eventPatch = {
conferenceData: {
createRequest: {requestId: "7qxalsvy0e"}
}
};

gapi.client.calendar.events.patch({
calendarId: "primary",
eventId: "7cbh8rpc10lrc0ckih9tafss99",
resource: eventPatch,
sendNotifications: true,
conferenceDataVersion: 1
}).execute(function(event) {
console.log("Conference created for event: %s", event.htmlLink);
});
The immediate response to this call might not yet contain the fully-populated conferenceData which is indicated by status pending:
"conferenceData": {
"createRequest": {
"requestId": "7qxalsvy0e",
"conferenceSolutionKey": {
"type": "hangoutsMeet"
},
"status": {
"statusCode": "pending"
}
}
}
Once the statusCode changes to success, the conference information is populated. Finally, if you are developing a Google Calendar client, you might also want to know beforehand which of the three Hangouts solutions (consumer Hangouts, classic Hangouts and Hangouts Meet) will be used to create the conference. You can get that information by checking allowedConferenceSolutionTypes in a calendar’s conferenceProperties.

To get started, check out the documentation page for managing conference data. We can’t wait to see what you build with these new features in the Google Calendar API.

Committed to storage APIs, retiring Realtime API


We launched Google Realtime API in 2013 to help developers build collaborative apps using familiar JSON-based data models, while leaving the complexities of real-time synchronization to the API. Since then, we've developed other fast, flexible cloud-based storage solutions like Google Cloud SQL and Google Cloud Firestore. As a result, we’ve decided to deprecate Realtime API in favor of these new, powerful solutions.

We’re investing heavily in Google Cloud Platform, as well as Firebase—our mobile development platform—to help developers build scalable, performant applications. While these solutions aren't a direct analog to the Drive Realtime API, we're confident they can meet most of your needs:
  • Google Cloud SQL: Fully-managed database service that makes it easy to set up, maintain, manage, and administer your relational PostgreSQL and MySQL databases in the cloud. 
  • Firebase Realtime Database: Cloud-hosted NoSQL database that lets you store and sync data between your users in real-time. 
  • Cloud Firestore: We recently announced Cloud Firestore to help developers build responsive apps that work regardless of network latency or Internet connectivity. If you're curious about Firebase Realtime Database vs. Cloud Firestore, we've got you covered.
Existing Realtime API client applications will continue to work normally until December 11, 2018, but we are no longer accepting new clients of the API. After the API is decommissioned, to facilitate migration, we will continue to provide a mechanism for applications to access document contents as JSON.

More specific deprecation timelines 

We know developers and partners have come to rely on Realtime API and that migration may be a significant effort. We hope that the deprecation timelines summarized below allow for a smooth transition.


November 28, 2017
Realtime API is no longer available for new projects.1
December 11, 2018
Realtime API documents become read-only, and attempts to modify document contents using the API fail.
January 15, 2019
Realtime API is shut down, but a JSON export API remains available.
1 Projects which accessed the Realtime API prior to November 28, 2017 (including your projects listed below) will continue to function as before. All other projects, including new projects, will be blocked from accessing the Realtime API.

Migration tips 

Applications using the Realtime API will need to migrate to another data store. Our migration guide provides instructions on how to export Realtime document data and also how that data can be imported into Google Cloud Firestore. After Realtime API is shut down, we will continue to provide a means for exporting Realtime document contents as JSON.

Additional information and support 

You can read more about the deprecation in our documentation. If you have questions that aren’t answered there, see the support page for how to get help.

Gmail add-ons framework now available to all developers



Email remains at the heart of how companies operate. That’s why earlier this year, we previewed Gmail Add-ons—a way to help businesses speed up workflows. Since then, we’ve seen partners build awesome applications, and beginning today, we’re extending the Gmail add-on preview to include all developers. Now anyone can start building a Gmail add-on.

Gmail Add-ons let you integrate your app into Gmail and extend Gmail to handle quick actions. They are built using native UI context cards that can include simple text dialogs, images, links, buttons and forms. The add-on appears when relevant, and the user is just a click away from your app's rich and integrated functionality.

Gmail Add-ons are easy to create. You only have to write code once for your add-on to work on both web and mobile, and you can choose from a rich palette of widgets to craft a custom UI. Create an add-on that contextually surfaces cards based on the content of a message. Check out this video to see how we created an add-on to collate email receipts and expedite expense reporting.

Per the video, you can see that there are three components to the app’s core functionality. The first component is getContextualAddOn()—this is the entry point for all Gmail Add-ons where data is compiled to build the card and render it within the Gmail UI. Since the add-on is processing expense reports from email receipts in your inbox, the createExpensesCard()parses the relevant data from the message and presents them in a form so your users can confirm or update values before submitting. Finally, submitForm() takes the data and writes a new row in an “expenses” spreadsheet in Google Sheets, which you can edit and tweak, and submit for approval to your boss.

Check out the documentation to get started with Gmail Add-ons, or if you want to see what it's like to build an add-on, go to the codelab to build ExpenseIt step-by-step. While you can't publish your add-on just yet, you can fill out this form to get notified when publishing is opened. We can’t wait to see what Gmail Add-ons you build!

[Q&A] Behind the scenes with Lucidchart: building new diagramming add-on in Google Slides


You might have seen that we recently announced new Google Slides add-ons. We worked closely with several technology partners to build these new add-on solutions to help speed up workflows. 

One partner, Lucidchart, worked closely with Google to create a new integration that brings added diagramming functionality to Slides. We sat down with Tim Winchester, engineering lead at Lucidchart, to learn more about how his team built the new Lucidchart add-on for Slides.

Tell us about the Google Slides add-on you built for Lucidchart. 

We built it as a sidebar add-on that allows users to insert diagrams directly into Google Slides from within Slides (instead of having to export diagrams from Lucidchart). You can also create a new Lucidchart diagram from within Slides, and simply select “Back to Slides” once you’re finished creating your diagram in the Lucidchart editor. You can modify an existing diagram by clicking “Edit” within Slides. This option will direct you to the Lucidchart editor so you can revise as needed. Once you’ve finished revising, or any time you know a diagram has been updated in Lucidchart, select the refresh button from the Lucidchart Diagrams sidebar.

What prompted you to create your add-on? 

Specifically, how did you envision your add-on would improve user experience? Lucidchart is a visual communication platform, but we know our users sometimes need to have their diagrams available in other places. One of the most popular uses for Lucidchart is in presentations, so an add-on for Slides was a natural fit.

Tell us about how you built your solution. 

Since we already had existing add-ons for Docs and Sheets, this project was less about building from scratch and more about adapting what we already had, then doing rewrites as needed. We started by abstracting app-specific functionality of our existing add-ons into a pluggable IntegratedApp interface. We then implemented the interface for Slides using the new SlidesApp API. Once we had reached feature parity, we created a few new additions, such as a “Refresh All Inserted Diagrams” button, which users could find more easily than a top bar menu entry.



At the same time, the Lucidchart add-on was undergoing a major UI overhaul, which was the most challenging and time-intensive part of the project. Because we liked the results of the UI update in Slides, we refactored the add-on code to make it more generalizable, then ported it back to our Docs and Sheets add-ons.

Did anything surprise you during the build? 

As a security measure, the sidebar iframe can only render elements within its borders, so we couldn’t simply throw a <div> into the center of the screen in client code. Instead, we had to fire an event that the Apps Script backend would handle to create a modal dialog, using printing scriptlets to add whatever data we needed into the dialog’s HTML. Thus, any JS object sent from the sidebar to a modal has to be serialized and deserialized in the process, which means that the sidebar cannot directly detect any events emitted by the modal.

Do you have any code snippets that you can share? 

Because we have multiple Google Apps Script add-ons that share lots of functionality, it was very useful to concentrate app-specific code and strings into a wrapper object (called IntegratedApp), which we then referenced elsewhere in the codebase instead of calling SlidesApp directly. So, in the click handler for the insert button, instead of writing this...
SlidesApp.getActivePresentation()
.getSelection()
.getCurrentPage()
.insertImage(image);

...we write this.
IntegratedApp.insertImage(image);

And then we keep the app-specific implementation in our IntegratedApp object (abridged for clarity):
var IntegratedApp = {
// direct mapping to function
createAddonMenu: SlidesApp.getUi().createAddonMenu.bind(SlidesApp.getUi()),

// wrapper to create consistent behavior across apps
insertImage: function(image) {
return SlidesApp.getActivePresentation()
.getSelection()
.getCurrentPage()
.insertImage(image);
},

// app-specific strings
phrases: {
docType: 'Slide',
name: 'Google Slides',
nameWithDocType: 'Google Slides Presentation'
}
};

This technique allows us to keep the same UI code and business logic across apps; we only need to change the implementation of the IntegratedApp object. So in Sheets (for example), our IntegratedApp.insertImage() function becomes:
insertImage: function(image) {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getActiveCell();

sheet.insertImage(image, cell.getColumn(), cell.getRow());
}

What advice would you give other developers looking to build similar add-ons? 

If you are planning to develop multiple similar add-ons that mainly differ in the G Suite app with which they integrate, you should find this technique of reducing the overall code amount by isolating duplicative code immensely useful.

After completing the first add-on, creating another add-on for a new G Suite app is just a matter of updating a new copy of IntegratedApp to work with the new app; the rest of the codebase can be commonly shared. In our case, it means that the updated UI was easily added to our Docs and Sheets add-on after we completed the Slides add-on.

Learn more about how you can create your own Slides add-ons or choose from a number of publicly available APIs to customize your G Suite applications. If you’re interested in becoming a Google Cloud technology partner, you can also join our partnership program.