פעולות אוניברסליות

פעולות אוניברסליות הן רכיבים של פריטי תפריט שמאפשרים למשתמש לפתוח דף אינטרנט חדש, להציג כרטיסי ממשק משתמש חדשים או להפעיל פונקציה ספציפית של Apps Script כשבוחרים אותם. הן דומות מאוד לפעולות בכרטיס, אבל פעולות אוניברסליות תמיד ממוקמות בכל כרטיס בתוסף, ללא קשר להקשר הנוכחי של התוסף.

שימוש בפעולות אוניברסליות מאפשר לוודא שלמשתמש תמיד תהיה גישה לפונקציונליות מסוימת, לא משנה באיזה חלק של התוסף הוא משתמש. ריכזנו כאן כמה תרחישי שימוש לדוגמה בפעולות אוניברסליות:

  • פותחים דף אינטרנט של הגדרות (או מציגים כרטיס הגדרות).
  • הצגת מידע עזרה למשתמש.
  • מתחילים תהליך עבודה חדש, כמו 'הוספת לקוח חדש'.
  • הצגת כרטיס שמאפשר למשתמש לשלוח משוב על התוסף.

אם יש לכם פעולה שלא תלויה בהקשר הנוכחי, כדאי להגדיר אותה כפעולה אוניברסלית.

שימוש בפעולות אוניברסליות

פעולות אוניברסליות מוגדרות במניפסט של פרויקט התוסף. אחרי שמגדירים פעולה אוניברסלית, היא תמיד זמינה למשתמשים בתוסף. אם המשתמש צופה בכרטיס, קבוצת הפעולות האוניברסליות שהגדרתם תמיד מופיעה בתפריט הכרטיס, אחרי פעולות הכרטיס שהגדרתם עבור אותו כרטיס. הפעולות האוניברסליות מופיעות בתפריטי הכרטיסים באותו סדר שבו הן מוגדרות במניפסט של התוסף.

הגדרת פעולות אוניברסליות

מגדירים פעולות אוניברסליות במניפסט של התוסף. פרטים נוספים מופיעים במאמר בנושא מניפסטים.

לכל פעולה, מציינים את הטקסט שיופיע בתפריט עבור הפעולה הזו. אחר כך אפשר לציין שדה openLink שמציין שהפעולה צריכה לפתוח ישירות דף אינטרנט בכרטיסייה חדשה. לחלופין, אפשר לציין שדה runFunction שמציין פונקציית קריאה חוזרת של Apps Script שתופעל כשבוחרים את הפעולה האוניברסלית.

כשמשתמשים ב-runFunction, פונקציית הקריאה החוזרת שצוינה בדרך כלל מבצעת אחת מהפעולות הבאות:

  • יוצר כרטיסים בממשק המשתמש להצגה מיידית על ידי החזרת אובייקט UniversalActionResponse בנוי.
  • פותח כתובת URL, אולי אחרי ביצוע משימות אחרות, על ידי החזרת אובייקט UniversalActionResponse שנבנה.
  • מבצע משימות ברקע שלא עוברות לכרטיס חדש או פותחות כתובת URL. במקרה כזה, פונקציית הקריאה החוזרת לא מחזירה כלום.

כשקוראים לפונקציית הקריאה החוזרת, מועבר אליה אובייקט אירוע שמכיל מידע על הכרטיס הפתוח ועל ההקשר של התוסף.

דוגמה

קטע הקוד הבא מציג קטע מתוך קובץ מניפסט של תוסף ל-Google Workspace שמשתמש בפעולות אוניברסליות בזמן הרחבת Gmail. הקוד מגדיר באופן מפורש את היקף המטא-נתונים כדי שהתוסף יוכל לקבוע מי שלח את ההודעה הפתוחה.

  "oauthScopes": [
    "https://www.googleapis.com/auth/gmail.addons.current.message.metadata"
  ],
  "addOns": {
    "common": {
      "name": "Universal Actions Only Addon",
      "logoUrl": "https://www.example.com/hosted/images/2x/my-icon.png",
      "openLinkUrlPrefixes": [
        "https://www.google.com",
        "https://www.example.com/urlbase"
      ],
      "universalActions": [{
          "label": "Open google.com",
          "openLink": "https://www.google.com"
        }, {
          "label": "Open contact URL",
          "runFunction": "openContactURL"
        }, {
          "label": "Open settings",
          "runFunction": "createSettingsResponse"
        }, {
          "label": "Run background sync",
          "runFunction": "runBackgroundSync"
      }],
      ...
    },
    "gmail": {
      "contextualTriggers": [
        {
          "unconditional": {},
          "onTriggerFunction": "getContextualAddOn"
        }
      ]
    },
    ...
  },
  ...

שלוש הפעולות האוניברסליות שמוגדרות בדוגמה הקודמת מבצעות את הפעולות הבאות:

  • פתיחת google.com פותחת את https://www.google.com בכרטיסייה חדשה.
  • הפונקציה Open contact URL מפעילה פונקציה שקובעת איזו כתובת URL לפתוח ואז פותחת אותה בכרטיסייה חדשה באמצעות אובייקט OpenLink. הקוד יוצר את כתובת ה-URL באמצעות כתובת האימייל של השולח.
  • הפונקציה Open settings מפעילה את הפונקציה createSettingsCards() שמוגדרת בפרויקט של סקריפט התוסף. הפונקציה הזו מחזירה אובייקט UniversalActionResponse תקין שמכיל קבוצה של כרטיסים עם הגדרות של תוספים ומידע נוסף. אחרי שהפונקציה מסיימת ליצור את האובייקט הזה, ממשק המשתמש מציג את רשימת הכרטיסים (ראו החזרת כמה כרטיסים).
  • הפונקציה Run background sync מריצה את הפונקציה runBackgroundSync() שמוגדרת בפרויקט הסקריפט של התוסף. הפונקציה הזו לא יוצרת כרטיסים, אלא מבצעת משימות רקע אחרות שלא משנות את ממשק המשתמש. מכיוון שהפונקציה לא מחזירה UniversalActionResponse, לא מוצג כרטיס חדש בממשק המשתמש כשהפונקציה מסתיימת. במקום זאת, בממשק המשתמש מוצג אינדיקטור טעינה מסתובב בזמן שהפונקציה פועלת.

דוגמה לאופן שבו אפשר ליצור את הפונקציות openContactURL(), createSettingsResponse() ו-runBackgroundSync():

/**
 * Open a contact URL.
 * @param {Object} e an event object
 * @return {UniversalActionResponse}
 */
function openContactURL(e) {
  // Activate temporary Gmail scopes, in this case so that the
  // open message metadata can be read.
  var accessToken = e.gmail.accessToken;
  GmailApp.setCurrentMessageAccessToken(accessToken);

  // Build URL to open based on a base URL and the sender's email.
  // This URL must be included in the openLinkUrlPrefixes whitelist.
  var messageId = e.gmail.messageId;
  var message = GmailApp.getMessageById(messageId);
  var sender = message.getFrom();
  var url = "https://www.example.com/urlbase/" + sender;
  return CardService.newUniversalActionResponseBuilder()
      .setOpenLink(CardService.newOpenLink()
          .setUrl(url))
      .build();
}

/**
 * Create a collection of cards to control the add-on settings and
 * present other information. These cards are displayed in a list when
 * the user selects the associated "Open settings" universal action.
 *
 * @param {Object} e an event object
 * @return {UniversalActionResponse}
 */
function createSettingsResponse(e) {
  return CardService.newUniversalActionResponseBuilder()
      .displayAddOnCards(
          [createSettingCard(), createAboutCard()])
      .build();
}

/**
 * Create and return a built settings card.
 * @return {Card}
 */
function createSettingCard() {
  return CardService.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))
          // ... continue adding widgets or other sections here ...
      ).build();   // Don't forget to build the card!
}

/**
 * Create and return a built 'About' informational card.
 * @return {Card}
 */
function createAboutCard() {
  return CardService.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>.'))
      // ... add other information widgets or sections here ...
      ).build();  // Don't forget to build the card!
}

/**
 * Run background tasks, none of which should alter the UI.
 * Also records the time of sync in the script properties.
 *
 * @param {Object} e an event object
 */
function runBackgroundSync(e) {
  var props = PropertiesService.getUserProperties();
  props.setProperty("syncTime", new Date().toString());

  syncWithContacts();  // Not shown.
  updateCache();       // Not shown.
  validate();          // Not shown.

  // no return value tells the UI to keep showing the current card.
}