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

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

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

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

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

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

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

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

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

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

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

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

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

דוגמה

קטע הקוד הבא מציג קטע מניפסט לדוגמה של תוסף ל-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 תקין שמכיל קבוצת כרטיסים עם הגדרות של התוסף ומידע נוסף. אחרי שהפונקציה מסיימת ליצור את האובייקט הזה, רשימת הכרטיסים מוצגת בממשק המשתמש (ראו החזרת מספר כרטיסים).
  • הפעלת סנכרון ברקע מפעילה את הפונקציה 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.
}