Makroları diğer e-tablolara kopyalama

Kodlama seviyesi: Orta
Süre: 30 dakika
Proje türü: Google Workspace Eklentisi

Hedefler

  • Çözümün ne işe yaradığını anlayın.
  • Apps Komut Dosyası hizmetlerinin çözümüne geçelim.
  • Ortamı ayarlayın.
  • Komut dosyasını ayarlayın.
  • Komut dosyasını çalıştırın.

Bu çözüm hakkında

Google E-Tablolar makrolarını bir e-tablodan diğerine manuel olarak kopyalamak zaman alır ve hataya açıktır. Bu Google Workspace eklentisi otomatik olarak bir komut dosyası projesini kopyalar ve bunu kullanıcı tarafından belirtilen bir e-tabloya ekler. Bununla birlikte Bu çözüm E-Tablolar makrolarına odaklandığından, bu çözümle ve kapsayıcıya bağlı tüm komut dosyalarını paylaşın.

Google Workspace Paylaşım Makrosu Eklentisinin ekran görüntüsü

İşleyiş şekli

Komut dosyası, orijinal e-tabloyu düzenlemeye başlar ve Apps Komut Dosyası projesinin kopyasını oluşturur. kullanıcı tarafından belirtilen e-tabloya bağlı.

Apps Komut Dosyası hizmetleri

Bu çözüm aşağıdaki hizmetleri kullanır:

  • URL Getirme hizmeti: Uygulamalara bağlanır Komut Dosyası API'sini kullanarak kaynak projeyi kopyalayıp bir kopyasını oluşturun.
  • Komut dosyası hizmeti: Apps Komut Dosyası'nı yetkilendirir. API'yi kullanarak ikinci bir yetkilendirme istemini önleyin.
  • E-tablo hizmeti: Hedefi açar e-tablo kullanarak kopyalayın.
  • Kart hizmeti: Eklentinin kullanıcı arayüzünü oluşturur.

Ön koşullar

Bu örneği kullanmak için aşağıdaki ön koşullara sahip olmanız gerekir:

Ortamınızı ayarlama

Google Cloud Console'da Cloud projenizi açma

Açık değilse kullanmayı düşündüğünüz Cloud projesini açın şu örneği inceleyelim:

  1. Google Cloud konsolunda Proje seçin sayfasına gidin.

    Cloud projesi seçin

  2. Kullanmak istediğiniz Google Cloud projesini seçin. Dilerseniz Proje oluştur'u tıklayıp ekrandaki talimatları da uygulayabilirsiniz. Google Cloud projesi oluşturursanız proje için faturalandırmayı etkinleştirmeniz gerekebilir.

Google Apps Komut Dosyası API'sini etkinleştirme

Bu hızlı başlangıç kılavuzu, Google Apps Komut Dosyası API'sini kullanır.

Google API'lerini kullanmadan önce bir Google Cloud projesinde etkinleştirmeniz gerekir. Tek bir Google Cloud projesinde bir veya daha fazla API'yi etkinleştirebilirsiniz.

Google Workspace eklentileri için izin ekranı yapılandırması gerekir. Yapılandırılıyor eklentinizin OAuth izin ekranı, Google'ın hangi bilgileri görüntüler.

  1. Google Cloud konsolunda Menü'ye gidin > API'lar ve Hizmetler > OAuth izin ekranı.

    OAuth izin ekranına gidin.

  2. Kullanıcı türü için Dahili'yi seçin ve ardından Oluştur'u tıklayın.
  3. Uygulama kayıt formunu doldurup Kaydet ve Devam Et'i tıklayın.
  4. Şimdilik kapsam eklemeyi atlayıp Kaydet ve Devam Et'i tıklayabilirsiniz. Gelecekte Google Workspace kuruluşu kullanıyorsanız Kullanıcı türü'nü Harici olarak değiştirmeniz ve ardından Uygulamanızın gerektirdiği yetkilendirme kapsamlarını ekleyin.

  5. Uygulama kaydı özetinizi inceleyin. Değişiklik yapmak için Düzenle'yi tıklayın. Uygulama Kontrol Paneline Dön'ü tıklayın.

Komut dosyasını ayarlama

Apps Komut Dosyası projesini oluşturma

  1. Şu düğmeyi tıklayarak Makro paylaş'ı açın Apps Komut Dosyası projesi.
    Projeyi açın
  2. Genel Bakış tıklayın.
  3. Genel bakış sayfasında Kopya oluştur'u Kopya oluşturma simgesi tıklayın.

Cloud projesi numarasını kopyalayın

  1. Google Cloud konsolunda Menü'ye gidin > IAM ve Yönetici > Ayarlar'a dokunun.

    IAM ve Yönetici Ayarları

  2. Proje numarası alanına değeri kopyalayın.

Apps Komut Dosyası projesinin Cloud projesini ayarlayın

  1. Kopyaladığınız Apps Komut Dosyası projenizde, Proje Ayarları'nı Proje ayarları simgesi tıklayın.
  2. Google Cloud Platform (GCP) Project bölümünde Projeyi değiştir seçeneğini tıklayın.
  3. GCP proje numarası alanına Google Cloud proje numarasını yapıştırın.
  4. Proje ayarla'yı tıklayın.

Test dağıtımı yükleme

  1. Kopyaladığınız Apps Komut Dosyası projenizde Düzenleyici'yi tıklayın. .
  2. UI.gs dosyasını açın ve Çalıştır'ı tıklayın. İstendiğinde komut dosyası.
  3. Dağıt > Dağıtımları test et'i tıklayın.
  4. Yükle > Bitti'yi tıklayın.

Makro komut dosyası ve e-tablo bilgilerini alma

  1. Makro içeren ve izniniz olan bir E-Tablolar e-tablosunu açın düzenleyin. Örnek bir e-tablo kullanmak için Örnek makro'nun bir kopyasını oluşturun. e-tablo ile gönderin.
  2. Uzantılar > Apps Komut Dosyası'nı tıklayın.
  3. Apps Komut Dosyası projesinde, Proje ayarları Proje ayarları simgesi.
  4. Komut dosyası kimliğinin altındaki Kopyala'yı tıklayın.
  5. Komut dosyası kimliğini daha sonraki bir adımda kullanmak üzere bir kenara ayırın.
  6. Makroyu eklemek istediğiniz yeni bir e-tablo açın veya yeni bir e-tablo oluşturun. Şunu yapmalısınız: ve e-tabloyu düzenleme iznine sahip olursunuz.
  7. E-tablo URL'sini kopyalayın ve daha sonraki bir adımda kullanmak üzere bir kenara ayırın.

Komut dosyasını çalıştırma

Kontrol paneli ayarlarınızda Google Apps Script API'nin etkinleştirildiğinden emin olun. Komut dosyanızı çalıştırmak için aşağıdaki bölümlerde yer alan adımları uygulayın.

Makroyu kopyalama

  1. E-Tablolar'da, sağ kenar çubuğunda Makro Paylaş eklentisini açın. Kopya oluşturma simgesi
  2. Kaynak makro'nun altına komut dosyası kimliğini yapıştırın.
  3. Hedef e-tablo altına e-tablonun URL'sini yapıştırın.
  4. Makro paylaş'ı tıklayın.
  5. Erişimi yetkilendir'i tıklayın ve eklentiyi yetkilendirin.
  6. 2-4. adımları tekrarlayın.

Kopyalanan makroyu aç

  1. Açık değilse makroyu kopyaladığınız e-tabloyu açın.
  2. Uzantılar > Apps Komut Dosyası'nı tıklayın.
  3. Kopyalanan Apps Komut Dosyası projesini görmüyorsanız Kontrol panelinde Google Apps Komut Dosyası etkin durumda olmalıdır. Ayarlar'ı ve Makroyu kopyala altında listelenen adımları tekrarlayın.

Kodu inceleyin

Bu çözüm için Apps Komut Dosyası kodunu incelemek üzere Aşağıdaki kaynak kodu görüntüleyin:

Kaynak kodu göster

Code.gs

solutions/add-on/share-macro/Code.js
// To learn how to use this script, refer to the documentation:
// https://developers.devsite.corp.google.com/apps-script/add-ons/share-macro

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Uses Apps Script API to copy source Apps Script project 
 * to destination Google Spreadsheet container.
 * 
 * @param {string} sourceScriptId - Script ID of the source project.
 * @param {string} targetSpreadsheetUrl - URL if the target spreadsheet.
 */
function shareMacro_(sourceScriptId, targetSpreadsheetUrl) {

  // Gets the source project content using the Apps Script API.
  const sourceProject = APPS_SCRIPT_API.get(sourceScriptId);
  const sourceFiles = APPS_SCRIPT_API.getContent(sourceScriptId);

  // Opens the target spreadsheet and gets its ID.
  const parentSSId = SpreadsheetApp.openByUrl(targetSpreadsheetUrl).getId();

  // Creates an Apps Script project that's bound to the target spreadsheet.
  const targetProjectObj = APPS_SCRIPT_API.create(sourceProject.title, parentSSId);

  // Updates the Apps Script project with the source project content.
  APPS_SCRIPT_API.updateContent(targetProjectObj.scriptId, sourceFiles);

}

/**
 * Function that encapsulates Apps Script API project manipulation. 
*/
const APPS_SCRIPT_API = {
  accessToken: ScriptApp.getOAuthToken(),

  /* APPS_SCRIPT_API.get
   * Gets Apps Script source project.
   * @param {string} scriptId - Script ID of the source project.
   * @return {Object} - JSON representation of source project.
   */
  get: function (scriptId) {
    const url = ('https://script.googleapis.com/v1/projects/' + scriptId);
    const options = {
      "method": 'get',
      "headers": {
        "Authorization": "Bearer " + this.accessToken
      },
      "muteHttpExceptions": true,
    };
    const res = UrlFetchApp.fetch(url, options);
    if (res.getResponseCode() == 200) {
      return JSON.parse(res);
    } else {
      console.log('An error occurred gettting the project details');
      console.log(res.getResponseCode());
      console.log(res.getContentText());
      console.log(res);
      return false;
    }
  },

  /* APPS_SCRIPT_API.create
   * Creates new Apps Script project in the target spreadsheet.
   * @param {string} title - Name of Apps Script project.
   * @param {string} parentId - Internal ID of target spreadsheet.
   * @return {Object} - JSON representation completed project creation.
   */
  create: function (title, parentId) {
    const url = 'https://script.googleapis.com/v1/projects';
    const options = {
      "headers": {
        "Authorization": "Bearer " + this.accessToken,
        "Content-Type": "application/json"
      },
      "muteHttpExceptions": true,
      "method": "POST",
      "payload": { "title": title }
    }
    if (parentId) {
      options.payload.parentId = parentId;
    }
    options.payload = JSON.stringify(options.payload);
    let res = UrlFetchApp.fetch(url, options);
    if (res.getResponseCode() == 200) {
      res = JSON.parse(res);
      return res;
    } else {
      console.log("An error occurred while creating the project");
      console.log(res.getResponseCode());
      console.log(res.getContentText());
      console.log(res);
      return false;
    }
  },
   /* APPS_SCRIPT_API.getContent
   * Gets the content of the source Apps Script project.
   * @param {string} scriptId - Script ID of the source project.
   * @return {Object} - JSON representation of Apps Script project content.
   */
   getContent: function (scriptId) {
    const url = "https://script.googleapis.com/v1/projects/" + scriptId + "/content";
    const options = {
      "method": 'get',
      "headers": {
        "Authorization": "Bearer " + this.accessToken
      },
      "muteHttpExceptions": true,
    };
    let res = UrlFetchApp.fetch(url, options);
    if (res.getResponseCode() == 200) {
      res = JSON.parse(res);
      return res['files'];
    } else {
      console.log('An error occurred obtaining the content from the source script');
      console.log(res.getResponseCode());
      console.log(res.getContentText());
      console.log(res);
      return false;
    }
  },

  /* APPS_SCRIPT_API.updateContent
   * Updates (copies) content from source to target Apps Script project.
   * @param {string} scriptId - Script ID of the source project.
   * @param {Object} files - JSON representation of Apps Script project content.
   * @return {boolean} - Result status of the function.
   */
  updateContent: function (scriptId, files) {
    const url = "https://script.googleapis.com/v1/projects/" + scriptId + "/content";
    const options = {
      "method": 'put',
      "headers": {
        "Authorization": "Bearer " + this.accessToken
      },
      "contentType": "application/json",
      "payload": JSON.stringify({ "files": files }),
      "muteHttpExceptions": true,
    };
    let res = UrlFetchApp.fetch(url, options);
    if (res.getResponseCode() == 200) {
      return true;
    } else {
      console.log(`An error occurred updating content of script ${scriptId}`);
      console.log(res.getResponseCode());
      console.log(res.getContentText());
      console.log(res);
      return false;
    }
  }
}

UI.gs

solutions/add-on/share-macro/UI.js
/**
 * Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Change application logo here (and in manifest) as desired.
const ADDON_LOGO = 'https://www.gstatic.com/images/branding/product/2x/apps_script_48dp.png';

/**
 * Callback function for rendering the main card.
 * @return {CardService.Card} The card to show the user.
 */
function onHomepage(e) {
  return createSelectionCard(e);
}

/**
 * Builds the primary card interface used to collect user inputs.
 * 
 * @param {Object} e - Add-on event object.
 * @param {string} sourceScriptId - Script ID of the source project.
 * @param {string} targetSpreadsheetUrl - URL of the target spreadsheet.
 * @param {string[]} errors - Array of error messages. 
 * 
 * @return {CardService.Card} The card to show to the user for inputs.
 */
function createSelectionCard(e, sourceScriptId, targetSpreadsheetUrl, errors) {

  // Configures card header.
  let cardHeader = CardService.newCardHeader()
    .setTitle('Share macros with other spreadheets!')
    .setImageUrl(ADDON_LOGO)
    .setImageStyle(CardService.ImageStyle.SQUARE);

  // If form errors exist, configures section with error messages.
  let showErrors = false;

  if (errors && errors.length) {
    showErrors = true;
    let msg = errors.reduce((str, err) => `${str}• ${err}<br>`, '');
    msg = `<b>Form submission errors:</b><br><font color="#ba0000">${msg}</font>`;

    // Builds error message section.
    sectionErrors = CardService.newCardSection()
      .addWidget(CardService.newDecoratedText()
        .setText(msg)
        .setWrapText(true));
  }

  // Configures source project section.
  let sectionSource = CardService.newCardSection()
    .addWidget(CardService.newDecoratedText()
      .setText('<b>Source macro</b><br>The Apps Script project to copy'))

    .addWidget(CardService.newTextInput()
      .setFieldName('sourceScriptId')
      .setValue(sourceScriptId || '')
      .setTitle('Script ID of the source macro')
      .setHint('You must have at least edit permission for the source spreadsheet to access its script project'))

    .addWidget(CardService.newTextButton()
      .setText('Find the script ID')
      .setOpenLink(CardService.newOpenLink()
        .setUrl('https://developers.google.com/apps-script/api/samples/execute')
        .setOpenAs(CardService.OpenAs.FULL_SIZE)
        .setOnClose(CardService.OnClose.NOTHING)));

  // Configures target spreadsheet section.
  let sectionTarget = CardService.newCardSection()
    .addWidget(CardService.newDecoratedText()
      .setText('<b>Target spreadsheet</b>'))

    .addWidget(CardService.newTextInput()
      .setFieldName('targetSpreadsheetUrl')
      .setValue(targetSpreadsheetUrl || '')
      .setHint('You must have at least edit permission for the target spreadsheet')
      .setTitle('Target spreadsheet URL'));

  // Configures help section.
  let sectionHelp = CardService.newCardSection()
    .addWidget(CardService.newDecoratedText()
      .setText('<b><font color=#c80000>NOTE: </font></b>' +
        'The Apps Script API must be turned on.')
      .setWrapText(true))

    .addWidget(CardService.newTextButton()
      .setText('Turn on Apps Script API')
      .setOpenLink(CardService.newOpenLink()
        .setUrl('https://script.google.com/home/usersettings')
        .setOpenAs(CardService.OpenAs.FULL_SIZE)
        .setOnClose(CardService.OnClose.NOTHING)));

  // Configures card footer with action to copy the macro.
  var cardFooter = CardService.newFixedFooter()
    .setPrimaryButton(CardService.newTextButton()
      .setText('Share macro')
      .setOnClickAction(CardService.newAction()
        .setFunctionName('onClickFunction_')));

  // Begins building the card.
  let builder = CardService.newCardBuilder()
    .setHeader(cardHeader);

  // Adds error section if applicable.
  if (showErrors) {
    builder.addSection(sectionErrors)
  }

  // Adds final sections & footer.
  builder
    .addSection(sectionSource)
    .addSection(sectionTarget)
    .addSection(sectionHelp)
    .setFixedFooter(cardFooter);

  return builder.build();
}

/**
 * Action handler that validates user inputs and calls shareMacro_
 * function to copy Apps Script project to target spreadsheet.
 * 
 * @param {Object} e - Add-on event object.
 * 
 * @return {CardService.Card} Responds with either a success or error card.
 */
function onClickFunction_(e) {

  const sourceScriptId = e.formInput.sourceScriptId;
  const targetSpreadsheetUrl = e.formInput.targetSpreadsheetUrl;

  // Validates inputs for errors.
  const errors = [];

  // Pushes an error message if the Script ID parameter is missing.
  if (!sourceScriptId) {
    errors.push('Missing script ID');
  } else {

    // Gets the Apps Script project if the Script ID parameter is valid.
    const sourceProject = APPS_SCRIPT_API.get(sourceScriptId);
    if (!sourceProject) {
      // Pushes an error message if the Script ID parameter isn't valid.
      errors.push('Invalid script ID');
    }
  }

  // Pushes an error message if the spreadsheet URL is missing.
  if (!targetSpreadsheetUrl) {
    errors.push('Missing Spreadsheet URL');
  } else
    try {
      // Tests for valid spreadsheet URL to get the spreadsheet ID.
      const ssId = SpreadsheetApp.openByUrl(targetSpreadsheetUrl).getId();
    } catch (err) {
      // Pushes an error message if the spreadsheet URL parameter isn't valid.
      errors.push('Invalid spreadsheet URL');
    }

  if (errors && errors.length) {
    // Redisplays form if inputs are missing or invalid.
    return createSelectionCard(e, sourceScriptId, targetSpreadsheetUrl, errors);

  } else {
    // Calls shareMacro function to copy the project.
    shareMacro_(sourceScriptId, targetSpreadsheetUrl);

    // Creates a success card to display to users.
    return buildSuccessCard(e, targetSpreadsheetUrl);
  }
}

/**
 * Builds success card to inform user & let them open the spreadsheet.
 * 
 * @param {Object} e - Add-on event object.
 * @param {string} targetSpreadsheetUrl - URL of the target spreadsheet.
 * 
 * @return {CardService.Card} Returns success card.
 */function buildSuccessCard(e, targetSpreadsheetUrl) {

  // Configures card header.
  let cardHeader = CardService.newCardHeader()
    .setTitle('Share macros with other spreadsheets!')
    .setImageUrl(ADDON_LOGO)
    .setImageStyle(CardService.ImageStyle.SQUARE);

  // Configures card body section with success message and open button.
  let sectionBody1 = CardService.newCardSection()
    .addWidget(CardService.newTextParagraph()
      .setText('Sharing process is complete!'))
    .addWidget(CardService.newTextButton()
      .setText('Open spreadsheet')
      .setOpenLink(CardService.newOpenLink()
        .setUrl(targetSpreadsheetUrl)
        .setOpenAs(CardService.OpenAs.FULL_SIZE)
        .setOnClose(CardService.OnClose.RELOAD_ADD_ON)));
  let sectionBody2 = CardService.newCardSection()
    .addWidget(CardService.newTextParagraph()
      .setText('If you don\'t see the copied project in your target spreadsheet,' +
       ' make sure you turned on the Apps Script API in the Apps Script dashboard.'))
    .addWidget(CardService.newTextButton()
      .setText("Check API")
      .setOpenLink(CardService.newOpenLink()
        .setUrl('https://script.google.com/home/usersettings')
        .setOpenAs(CardService.OpenAs.FULL_SIZE)
        .setOnClose(CardService.OnClose.RELOAD_ADD_ON)));

  // Configures the card footer with action to start new process.
  let cardFooter = CardService.newFixedFooter()
    .setPrimaryButton(CardService.newTextButton()
      .setText('Share another')
      .setOnClickAction(CardService.newAction()
        .setFunctionName('onHomepage')));

  return builder = CardService.newCardBuilder()
    .setHeader(cardHeader)
    .addSection(sectionBody1)
    .addSection(sectionBody2)
    .setFixedFooter(cardFooter)
    .build();
 }

appsscript.json

solutions/add-on/share-macro/appsscript.json
{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/drive.readonly",
    "https://www.googleapis.com/auth/script.projects"
  ],
    "urlFetchWhitelist": [
    "https://script.googleapis.com/"
  ],
  "addOns": {
    "common": {
      "name": "Share Macro",
      "logoUrl": "https://www.gstatic.com/images/branding/product/2x/apps_script_48dp.png",
      "layoutProperties": {
        "primaryColor": "#188038",
        "secondaryColor": "#34a853"
      },
      "homepageTrigger": {
        "runFunction": "onHomepage"
      }
    },
    "sheets": {}
  }
}

Katkıda bulunanlar

Bu örnek, Google Geliştirici Uzmanları'nın yardımıyla Google tarafından yönetilir.

Sonraki adımlar