معاينة الروابط باستخدام الشرائح الذكية (معاينة مطوّر البرامج)

<a href="/intl/ar/ads/">البرنامج الإعلاني</a>

توضّح هذه الصفحة كيفية إنشاء إضافة Google Workspace تسمح لمستخدمي "مستندات Google" بمعاينة الروابط من خدمة تابعة لجهة خارجية.

يمكن أن ترصد إضافة Google Workspace روابط الخدمة وتطلب من مستخدمي "مستندات Google" معاينتها. يمكنك ضبط إضافة لمعاينة معاينة أنماط متعدّدة لعناوين URL، مثل الروابط المؤدية إلى طلبات الحصول على الدعم والعملاء المحتملين للمبيعات والملفات الشخصية للموظفين.

لمعاينة الروابط في مستند على "مستندات Google"، يتفاعل المستخدمون مع الشرائح الذكية والبطاقات:

معاينة المستخدم لبطاقة

عندما يكتب المستخدمون عنوان URL أو يلصقونه في مستند، سيطلب منهم "مستندات Google" استبدال الرابط بشريحة ذكية. تعرض الشريحة الذكية رمزًا وعنوانًا قصيرًا أو وصفًا لمحتوى الرابط. وعندما يمرّر المستخدم مؤشر الماوس فوق الشريحة، ستظهر له واجهة بطاقة تعرض مزيدًا من المعلومات عن الملف أو الرابط.

يوضّح الفيديو التالي طريقة تحويل المستخدم لرابط إلى شريحة ذكية ومعاينة بطاقة:

المتطلبات الأساسية

برمجة تطبيقات

Node.js

لغة Python

لغة Java

إجراء اختياري: إعداد المصادقة على خدمة تابعة لجهة خارجية

إذا كانت الإضافة مرتبطة بخدمة تتطلب تفويضًا، يجب على المستخدمين المصادقة على الخدمة لمعاينة الروابط. وهذا يعني أنه عندما يلصق المستخدمون رابطًا من خدمتك في مستند على "مستندات Google" للمرة الأولى، يجب أن تستدعي الإضافة مسار التفويض.

لإعداد خدمة OAuth أو رسالة مطالبة مُخصَّصة للتفويض، يُرجى الاطِّلاع على أحد الأدلة التالية:

يوضّح هذا القسم طريقة إعداد معاينات الروابط للإضافة، والتي تتضمّن الخطوات التالية:

  1. اضبط معاينات الروابط في مورد النشر أو ملف البيان الخاص بالإضافة.
  2. أنشئ شريحة ذكية وواجهة الواجهة للروابط.

ضبط معاينات الروابط

لضبط معاينات الروابط، حدِّد الأقسام والحقول التالية في مورد نشر الإضافة أو ملف البيان:

  1. ضمن القسم addOns، أضِف الحقل docs لتوسيع "مستندات Google".
  2. في الحقل docs، نفِّذ عامل التشغيل linkPreviewTriggers الذي يتضمّن runFunction (تحدّد هذه الدالة في القسم التالي، إنشاء الشريحة الذكية والبطاقة).

    للتعرّف على الحقول التي يمكنك تحديدها في مشغِّل linkPreviewTriggers، يمكنك الاطّلاع على المستندات المرجعية الخاصة بملفات بيان "برمجة تطبيقات Google" أو موارد النشر لأوقات التشغيل الأخرى.

  3. في الحقل oauthScopes، أضِف النطاق https://www.googleapis.com/auth/workspace.linkpreview حتى يتمكّن المستخدمون من تفويض الإضافة لمعاينة الروابط نيابةً عنهم.

على سبيل المثال، راجِع القسمَين oauthScopes وaddons من مورد نشر يضبط معاينات الروابط لخدمة الدعم:

{
  "oauthScopes": [
    "https://www.googleapis.com/auth/workspace.linkpreview"
  ],
  "addOns": {
    "common": {
      "name": "Preview support cases",
      "logoUrl": "https://www.example.com/images/company-logo.png",
      "layoutProperties": {
        "primaryColor": "#dd4b39"
      }
    },
    "docs": {
      "linkPreviewTriggers": [
        {
          "runFunction": "caseLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "logoUrl": "https://www.example.com/images/support-icon.png",
          "localizedLabelText": {
            "es": "Caso de soporte"
          }
        }
      ]
    }
  }
}

في المثال، روابط معاينة إضافة Google Workspace لخدمة طلب الحصول على الدعم الخاصة بالشركة. تحدّد الإضافة ثلاثة أنماط لعناوين URL لمعاينة الروابط. عندما يتطابق رابط مع أحد أنماط عناوين URL في مستند "مستندات Google"، تنشئ دالة رد الاتصال caseLinkPreview شريحة وبطاقة ذكية وتعرضها.

إنشاء الشريحة الذكية والبطاقة

لعرض شريحة ذكية وبطاقة لرابط، يجب تنفيذ أي دوال حدّدتها في الكائن linkPreviewTriggers.

عندما يتفاعل المستخدم مع رابط يتطابق مع نمط عنوان URL محدّد، يتم تنشيط عامل التشغيل linkPreviewTriggers ويتم تمرير دالة رد الاتصال إلى عنصر الحدث docs.matchedUrl.url كوسيطة. يمكنك استخدام حمولة هذا الحدث لإنشاء شريحة ذكية وبطاقة لمعاينة الرابط.

على سبيل المثال، بالنسبة إلى إضافة تحدّد نمط عنوان URL example.com/cases، إذا عاين المستخدم الرابط https://www.example.com/cases/123456، سيتم عرض حمولة الحدث التالية:

JSON

{
  "docs": {
    "matchedUrl": {
        "url": "https://www.example.com/support/cases/123456"
    }
  }
}

لإنشاء واجهة البطاقة، يمكنك استخدام التطبيقات المصغّرة لعرض معلومات عن الرابط. يمكنك أيضًا إنشاء إجراءات تتيح للمستخدمين فتح الرابط أو تعديل محتواه. للحصول على قائمة بالأدوات والإجراءات المتاحة، يُرجى الاطلاع على المكوّنات المعتمدة لبطاقات المعاينة.

لإنشاء الشريحة الذكية والبطاقة لمعاينة الرابط:

  1. نفِّذ الدالة التي حدّدتها في قسم linkPreviewTriggers من مورد نشر الإضافة أو ملف البيان:
    1. يجب أن تقبل الدالة عنصر كائن حدث يحتوي على docs.matchedUrl.url كوسيطة وتعرض عنصر Card واحدًا.
    2. إذا كانت الخدمة تتطلّب تفويضًا، يجب أن تستدعي الدالة أيضًا مسار التفويض.
  2. لكل بطاقة معاينة، نفِّذ دوال معاودة الاتصال المستخدَمة لتوفير تفاعل الأداة للواجهة. على سبيل المثال، إذا أدرجت زرًا في الواجهة، يجب أن تحتوي على زر Action مرفق ودالة معاودة اتصال يتم تنفيذها عندما يتم النقر على الزر.

ينشئ الرمز التالي دالة معاودة الاتصال caseLinkPreview:

برمجة تطبيقات

Apps-script/preview-links/preview-link.gs
/**
* Entry point for a support case link preview
*
* @param {!Object} event
* @return {!Card}
*/
// Creates a function that passes an event object as a parameter.
function caseLinkPreview(event) {

  // If the event object URL matches a specified pattern for support case links.
  if (event.docs.matchedUrl.url) {

    // Uses the event object to parse the URL and identify the case ID.
    const segments = event.docs.matchedUrl.url.split('/');
    const caseId = segments[segments.length - 1];

    // Builds a preview card with the case ID, title, and description
    const caseHeader = CardService.newCardHeader()
      .setTitle(`Case ${caseId}: Title bar is broken.`);
    const caseDescription = CardService.newTextParagraph()
      .setText('Customer can\'t view title on mobile device.');

    // Returns the card.
    // Uses the text from the card's header for the title of the smart chip.
    return CardService.newCardBuilder()
      .setHeader(caseHeader)
      .addSection(CardService.newCardSection().addWidget(caseDescription))
      .build();
  }
}

Node.js

Node/preview-links/index.js
/**
 * 
 * A support case link preview.
 *
 * @param {!string} url
 * @return {!Card}
 */
function caseLinkPreview(url) {

  // Parses the URL to identify the case ID.
  const segments = url.split('/');
  const caseId = segments[segments.length - 1];

  // Returns the card.
  // Uses the text from the card's header for the title of the smart chip.
  return {
    header: {
      title: `Case ${caseId}: Title bar is broken.`
    },
    sections: [{
      widgets: [{
        textParagraph: {
          text: `Customer can't view title on mobile device.`
        }
      }]
    }]
  };
}

لغة Python

python/preview-links/main.py

def case_link_preview(url):
    """A support case link preview.
    Args:
      url: The case link.
    Returns:
      A case link preview card.
    """

    # Parses the URL to identify the case ID.
    segments = url.split("/")
    case_id = segments[-1]

    # Returns the card.
    # Uses the text from the card's header for the title of the smart chip.
    return {
        "header": {"title": f"Case {case_id}: Title bar is broken."},
        "sections": [
            {
                "widgets": [
                    {
                        "textParagraph": {
                            "text": "Customer can't view title on mobile device."
                        }
                    }
                ]
            }
        ],
    }

لغة Java

java/preview-links/src/main/java/PreviewLink.java
/**
 * Creates a case link preview card.
 *
 * @param url A URL.
 * @return A case link preview card.
 */
Card caseLinkPreview(String url) {
  String[] segments = url.split("/");
  String caseId = segments[segments.length - 1];

  CardHeader cardHeader = new CardHeader();
  cardHeader.setTitle(String.format("Case %s: Title bar is broken.", caseId));

  TextParagraph textParagraph = new TextParagraph();
  textParagraph.setText("Customer can't view title on mobile device.");

  WidgetMarkup widget = new WidgetMarkup();
  widget.setTextParagraph(textParagraph);
  Section section = new Section();
  section.setWidgets(List.of(widget));

  Card card = new Card();
  card.setHeader(cardHeader);
  card.setSections(List.of(section));

  return card;
}

المكوّنات المعتمدة لبطاقات المعاينة

تتوافق إضافات Google Workspace مع الأدوات والإجراءات التالية لبطاقات معاينة الرابط:

برمجة تطبيقات

حقل خدمة البطاقة Type
TextParagraph تطبيق مصغّر
DecoratedText تطبيق مصغّر
Image تطبيق مصغّر
IconImage تطبيق مصغّر
ButtonSet تطبيق مصغّر
TextButton تطبيق مصغّر
ImageButton تطبيق مصغّر
Grid تطبيق مصغّر
Divider تطبيق مصغّر
OpenLink الإجراء
Navigation الإجراء
هو المتاح فقط باستخدام طريقة updateCard.

JSON

حقل البطاقة (google.apps.card.v1) Type
TextParagraph تطبيق مصغّر
DecoratedText تطبيق مصغّر
Image تطبيق مصغّر
Icon تطبيق مصغّر
ButtonList تطبيق مصغّر
Button تطبيق مصغّر
Grid تطبيق مصغّر
Divider تطبيق مصغّر
OpenLink الإجراء
Navigation الإجراء
متوافق فقط مع updateCard.

مثال كامل: إضافة طلب الحصول على الدعم

يوضّح المثال التالي إضافة Google Workspace التي تعمل على معاينة الروابط المؤدية إلى طلبات الحصول على الدعم للشركة وملفاتها الشخصية للموظفين.

يوضّح المثال ما يلي:

  • رابط المعاينات إلى طلبات الحصول على الدعم، مثل https://www.example.com/support/cases/1234. تعرض الشريحة الذكية رمز الدعم، وتشمل بطاقة المعاينة رقم تعريف الطلب ووصفًا.
  • معاينة روابط وكلاء الدعم، مثل https://www.example.com/people/rosario-cruz. تعرض الشريحة الذكية رمزًا لشخص، وتتضمّن بطاقة المعاينة اسم الموظف وعنوان بريده الإلكتروني وعنوانه الوظيفي وصورة ملفه الشخصي.
  • في حال ضبط لغة المستخدم على الإسبانية، تترجم الشريحة الذكية labelText إلى الإسبانية.

مورد النشر

برمجة تطبيقات

{
  "timeZone": "America/New_York",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/workspace.linkpreview"
  ],
  "addOns": {
    "common": {
      "name": "Preview support cases",
      "logoUrl": "https://developers.google.com/workspace/add-ons/images/link-icon.png",
      "layoutProperties": {
        "primaryColor": "#dd4b39"
      }
    },
    "docs": {
      "linkPreviewTriggers": [
        {
          "runFunction": "caseLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "localizedLabelText": {
            "es": "Caso de soporte"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png"
        },
        {
          "runFunction": "peopleLinkPreview",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "people"
            }
          ],
          "labelText": "People",
          "localizedLabelText": {
            "es": "Personas"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/person-icon.png"
        }
      ]
    }
  }
}

JSON

{
  "oauthScopes": [
    "https://www.googleapis.com/auth/workspace.linkpreview"
  ],
  "addOns": {
    "common": {
      "name": "Preview support cases",
      "logoUrl": "https://developers.google.com/workspace/add-ons/images/link-icon.png",
      "layoutProperties": {
        "primaryColor": "#dd4b39"
      }
    },
    "docs": {
      "linkPreviewTriggers": [
        {
          "runFunction": "URL",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "support/cases"
            },
            {
              "hostPattern": "*.example.com",
              "pathPrefix": "cases"
            },
            {
              "hostPattern": "cases.example.com"
            }
          ],
          "labelText": "Support case",
          "localizedLabelText": {
            "es": "Caso de soporte"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png"
        },
        {
          "runFunction": "URL",
          "patterns": [
            {
              "hostPattern": "example.com",
              "pathPrefix": "people"
            }
          ],
          "labelText": "People",
          "localizedLabelText": {
            "es": "Personas"
          },
          "logoUrl": "https://developers.google.com/workspace/add-ons/images/person-icon.png"
        }
      ]
    }
  }
}

الرمز

برمجة تطبيقات

Apps-script/preview-links/preview-link.gs
/**
* Entry point for a support case link preview
*
* @param {!Object} event
* @return {!Card}
*/
// Creates a function that passes an event object as a parameter.
function caseLinkPreview(event) {

  // If the event object URL matches a specified pattern for support case links.
  if (event.docs.matchedUrl.url) {

    // Uses the event object to parse the URL and identify the case ID.
    const segments = event.docs.matchedUrl.url.split('/');
    const caseId = segments[segments.length - 1];

    // Builds a preview card with the case ID, title, and description
    const caseHeader = CardService.newCardHeader()
      .setTitle(`Case ${caseId}: Title bar is broken.`);
    const caseDescription = CardService.newTextParagraph()
      .setText('Customer can\'t view title on mobile device.');

    // Returns the card.
    // Uses the text from the card's header for the title of the smart chip.
    return CardService.newCardBuilder()
      .setHeader(caseHeader)
      .addSection(CardService.newCardSection().addWidget(caseDescription))
      .build();
  }
}


/**
* Entry point for an employee profile link preview
*
* @param {!Object} event
* @return {!Card}
*/
function peopleLinkPreview(event) {

  // If the event object URL matches a specified pattern for employee profile links.
  if (event.docs.matchedUrl.url) {

    // Builds a preview card with an employee's name, title, email, and profile photo.
    const userHeader = CardService.newCardHeader().setTitle("Rosario Cruz");
    const userImage = CardService.newImage()
      .setImageUrl("https://developers.google.com/workspace/add-ons/images/employee-profile.png");
    const userInfo = CardService.newDecoratedText()
      .setText("rosario@example.com")
      .setBottomLabel("Case Manager")
      .setIcon(CardService.Icon.EMAIL);
    const userSection = CardService.newCardSection()
      .addWidget(userImage)
      .addWidget(userInfo);

    // Returns the card. Uses the text from the card's header for the title of the smart chip.
    return CardService.newCardBuilder()
      .setHeader(userHeader)
      .addSection(userSection)
      .build();
  }
}

Node.js

Node/preview-links/index.js
const UrlParser = require('url');

/**
 * Responds to any HTTP request.
 *
 * @param {Object} req HTTP request context.
 * @param {Object} res HTTP response context.
 */
exports.createLinkPreview = (req, res) => {
  const event = req.body;
  if (event.docs.matchedUrl.url) {
    res.json(createCard(event.docs.matchedUrl.url));
  }
};

/**
 * Creates a preview link card for either a case link or people link.
 * 
 * @param {!String} url
 * @return {!Card}
 */
function createCard(url) {
  const parsedUrl = UrlParser.parse(url);
  if (parsedUrl.hostname === 'www.example.com') {
    if (parsedUrl.path.startsWith('/support/cases/')) {
      return caseLinkPreview(url);
    }

    if (parsedUrl.path.startsWith('/people/')) {
      return peopleLinkPreview();
    }
  }
}


/**
 * 
 * A support case link preview.
 *
 * @param {!string} url
 * @return {!Card}
 */
function caseLinkPreview(url) {

  // Parses the URL to identify the case ID.
  const segments = url.split('/');
  const caseId = segments[segments.length - 1];

  // Returns the card.
  // Uses the text from the card's header for the title of the smart chip.
  return {
    header: {
      title: `Case ${caseId}: Title bar is broken.`
    },
    sections: [{
      widgets: [{
        textParagraph: {
          text: `Customer can't view title on mobile device.`
        }
      }]
    }]
  };
}


/**
 * An employee profile link preview.
 *
 * @return {!Card}
 */
function peopleLinkPreview() {

  // Builds a preview card with an employee's name, title, email, and profile photo.
  // Returns the card. Uses the text from the card's header for the title of the smart chip.
  return {
    header: {
      title: "Rosario Cruz"
    },
    sections: [{
      widgets: [
        {
          image: {
            imageUrl: 'https://developers.google.com/workspace/add-ons/images/employee-profile.png'
          }
        }, {
          keyValue: {
            icon: "EMAIL",
            content: "rosario@example.com",
            bottomLabel: "Case Manager"
          }
        }
      ]
    }]
  };
}

لغة Python

python/preview-links/main.py
from typing import Any, Mapping
from urllib.parse import urlparse

import flask
import functions_framework


@functions_framework.http
def create_link_preview(req: flask.Request):
    """Responds to any HTTP request.
    Args:
      req: HTTP request context.
    Returns:
      The response object.
    """
    event = req.get_json(silent=True)
    if event["docs"]["matchedUrl"]["url"]:
        return create_card(event["docs"]["matchedUrl"]["url"])


def create_card(url):
    """Creates a preview link card for either a case link or people link.
    Args:
      url: The matched url.
    Returns:
      A case link preview card or a people link preview card.
    """
    parsed_url = urlparse(url)
    if parsed_url.hostname != "www.example.com":
        return {}

    if parsed_url.path.startswith("/support/cases/"):
        return case_link_preview(url)

    if parsed_url.path.startswith("/people/"):
        return people_link_preview()

    return {}




def case_link_preview(url):
    """A support case link preview.
    Args:
      url: The case link.
    Returns:
      A case link preview card.
    """

    # Parses the URL to identify the case ID.
    segments = url.split("/")
    case_id = segments[-1]

    # Returns the card.
    # Uses the text from the card's header for the title of the smart chip.
    return {
        "header": {"title": f"Case {case_id}: Title bar is broken."},
        "sections": [
            {
                "widgets": [
                    {
                        "textParagraph": {
                            "text": "Customer can't view title on mobile device."
                        }
                    }
                ]
            }
        ],
    }




def people_link_preview():
    """An employee profile link preview.
    Returns:
      A people link preview card.
    """

    # Builds a preview card with an employee's name, title, email, and profile photo.
    # Returns the card. Uses the text from the card's header for the title of the smart chip.
    return {
        "header": {"title": "Rosario Cruz"},
        "sections": [
            {
                "widgets": [
                    {
                        "image": {
                            "imageUrl": "https:#developers.google.com/workspace/add-ons/images/employee-profile.png"
                        }
                    },
                    {
                        "keyValue": {
                            "icon": "EMAIL",
                            "content": "rosario@example.com",
                            "bottomLabel": "Case Manager",
                        }
                    },
                ]
            }
        ],
    }

لغة Java

java/preview-links/src/main/java/PreviewLink.java
import com.google.api.services.chat.v1.model.Card;
import com.google.api.services.chat.v1.model.CardHeader;
import com.google.api.services.chat.v1.model.Image;
import com.google.api.services.chat.v1.model.KeyValue;
import com.google.api.services.chat.v1.model.Section;
import com.google.api.services.chat.v1.model.TextParagraph;
import com.google.api.services.chat.v1.model.WidgetMarkup;
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

public class PreviewLink implements HttpFunction {
  private static final Gson gson = new Gson();

  /**
   * Responds to any HTTP request.
   *
   * @param request  An HTTP request context.
   * @param response An HTTP response context.
   */
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonObject body = gson.fromJson(request.getReader(), JsonObject.class);
    String url = body.getAsJsonObject("docs")
        .getAsJsonObject("matchedUrl")
        .get("url")
        .getAsString();

    response.getWriter().write(gson.toJson(createCard(url)));
  }

  /**
   * Creates a preview link card for either a case link or people link.
   *
   * @param url A URL.
   * @return A case link preview card or a people link preview card.
   */
  Card createCard(String url) throws MalformedURLException {
    URL parsedURL = new URL(url);

    if (!parsedURL.getHost().equals("www.example.com")) {
      return new Card();
    }

    if (parsedURL.getPath().startsWith("/support/cases/")) {
      return caseLinkPreview(url);
    }

    if (parsedURL.getPath().startsWith("/people/")) {
      return peopleLinkPreview();
    }

    return new Card();
  }


  /**
   * Creates a case link preview card.
   *
   * @param url A URL.
   * @return A case link preview card.
   */
  Card caseLinkPreview(String url) {
    String[] segments = url.split("/");
    String caseId = segments[segments.length - 1];

    CardHeader cardHeader = new CardHeader();
    cardHeader.setTitle(String.format("Case %s: Title bar is broken.", caseId));

    TextParagraph textParagraph = new TextParagraph();
    textParagraph.setText("Customer can't view title on mobile device.");

    WidgetMarkup widget = new WidgetMarkup();
    widget.setTextParagraph(textParagraph);
    Section section = new Section();
    section.setWidgets(List.of(widget));

    Card card = new Card();
    card.setHeader(cardHeader);
    card.setSections(List.of(section));

    return card;
  }


  /**
   * Creates a people link preview card.
   *
   * @return A people link preview card.
   */
  Card peopleLinkPreview() {
    CardHeader cardHeader = new CardHeader();
    cardHeader.setTitle("Rosario Cruz");

    Image image = new Image();
    image.setImageUrl("https://developers.google.com/workspace/add-ons/images/employee-profile.png");

    WidgetMarkup imageWidget = new WidgetMarkup();
    imageWidget.setImage(image);

    KeyValue keyValue = new KeyValue();
    keyValue.setIcon("EMAIL");
    keyValue.setContent("rosario@example.com");
    keyValue.setBottomLabel("Case Manager");

    WidgetMarkup keyValueWidget = new WidgetMarkup();
    keyValueWidget.setKeyValue(keyValue);

    Section section = new Section();
    section.setWidgets(List.of(imageWidget, keyValueWidget));

    Card card = new Card();
    card.setHeader(cardHeader);
    card.setSections(List.of(section));

    return card;
  }

}