Давайте расширим Google Диск с помощью Apps Script, чтобы создать простую надстройку, использовать CardService для пользовательского интерфейса, где мы выберем несколько электронных таблиц и передадим их на следующую карту с навигацией. Вы можете найти другие мои блоги в Google Apps Scripts справа. здесь.


вступление

Привет, это Нибес Хадка из салона кодирования Хадки. Я написал этот блог, потому что лично нахожу документацию слишком сложной для начинающих. Также очень сложно найти блоги на скриптах приложений Google. Итак, этот блог для начинающих был создан, чтобы вы начали. Я считаю, что этот блог даст вам почти 20%, которые вам понадобятся для завершения почти 80% ваших проектов.


Предварительное требование

Вам понадобятся знания JavaScript и доступ к Google Drive. Я использую сценарий приложений, но если вы хотите разрабатывать в локальной среде, вы найдете это настраивать руководство полезно.


Настройки

Направляйтесь к приборная доскаи создайте новый файл сценария для проекта. После этого нам нужно подготовить наши проекты, как указано ниже.


домашние страницы

Согласно документацияесть два типа домашних страниц, когда вы разрабатываете надстройки для Диска: Контекстуальный а также Неконтекстный.

Неконтекстный — это начальное отображение, когда ничего не происходит, например, первый экран, который отображается после нажатия надстройки. Контекстный — это домашняя страница/экран, который появляется, когда мы выполняем определенное действие, например, выбираем файлы на диске.

Чтобы функции сценариев приложений вызывались на диске, нам нужно назначить эти функции соответствующим триггерам для надстройки диска в манифесте (приложенияскрипт.json) файл.


Триггеры домашней страницы

Когда пользователь нажимает на значок надстройки, drive.homepageТриггер вызывается метод. Затем этот метод ищет функцию, а затем вызывает указанную функцию в манифесте (appsscript.json) для дальнейших операций.


Триггер выбранного элемента

Для контекстных триггеров мы назначим функцию в сценарии нашего приложения на drive.onItemSelectedTrigger в файле манифеста.


Области действия Oauth

Для работы надстройки диска пользователь должен предоставить разрешение на доступ. Список разрешений называется Сферы. Подробные сведения об областях действия для конкретных дисков см. здесь. Нам нужно указать области видимости в приложенияскрипт.json файл снова в виде списка с «oauthScopes».

Примечание. Если ваш файл appsscript.json скрыт, перейдите в настройки и проверьте Показать файл манифеста «appsscript.json» в редакторе флажок.

Ознакомьтесь с файлом манифеста для этого проекта ниже.

{
 "timeZone": "Asia/Kathmandu",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
  "oauthScopes": [
    "
    "
    "
    "
    "
  ],
  "addOns": {
    "common": {
      "name": "Drive Extension with Apps Script",
      "logoUrl": "provide image URL to be used as logo",
      "layoutProperties": {
        "primaryColor": "#41f470",
        "secondaryColor": "#ab2699"
      }
    },
    "drive": {
      "homepageTrigger": {
        "runFunction": "onDriveHomePageOpen",
        "enabled": true
      },
      "onItemsSelectedTrigger": {
        "runFunction": "onDriveItemsSelected"
      }
    }
  }
}
Войти в полноэкранный режим

Выйти из полноэкранного режима


Использование скрипта приложений для доступа к Google Диску

Теперь в корневой папке проекта создайте два файла, карты а также главный.


Назначение функций сценариев приложений триггерам

главный

// On homepage trigger function
let onDriveHomePageOpen = () => homepageCard();

// On Item selected Trigger function
let onDriveItemsSelected = (e) => itemSelectedCard(e);

Войти в полноэкранный режим

Выйти из полноэкранного режима

onDriveHomePageOpen а также onDriveItemsSelected — это две функции, которые мы ранее назначили в файле манифеста. Эти функции, в свою очередь, вызывают другие функции, которые мы создадим позже. Если при сохранении файла появляется всплывающее окно с ошибкой, отклоните его на данный момент.


Проектирование поведения карт

Давайте создадим простую карточку домашней страницы, которая будет назначена нашему неконтекстному триггеру на карты файл.


Создать карточку домашней страницы

let homepageCard = () => {
// Create a card with a header section
  let card = CardService.newCardBuilder().setHeader(CardService.newCardHeader());
// create card section 
  let section = CardService.newCardSection();

// add heading 
  let decoratedText = CardService.newDecoratedText()
    .setText("Select Files To Update");

// add text as a widget to the card section
  section.addWidget(decoratedText);

// add the section to the card 
  card.addSection(section);

// return card as build
  return card.build();

}

Войти в полноэкранный режим

Выйти из полноэкранного режима

Карты можно использовать для создать пользовательский интерфейс для надстроек для гугл диска.

Это блог для начинающих, поэтому я не сосредоточен на стилизации.


Создать неконтекстную карточку

Теперь давайте возьмем еще одну карту, на которую мы будем отвечать за контекстный триггер в том же файле. Но давайте разделим этот код на разделы, чтобы было понятно.


1. Создайте простой интерфейс карты.

let itemSelectedCard = (e) => {

  // Initial UI
  let card = CardService.newCardBuilder().setHeader(CardService.newCardHeader().setTitle("Select Sheets Update Master Sheet"));
  let filesSection = CardService.newCardSection()
  filesSection.setHeader("Selected Files");
  return card.build();
}
Войти в полноэкранный режим

Выйти из полноэкранного режима


2. Отобразить выбранные файлы в пользовательском интерфейсе.

var itemSelectedCard = (e) => {

  // Initial UI
  let card = CardService.newCardBuilder().setHeader(CardService.newCardHeader().setTitle("Select Sheets Update Master Sheet"));
  let filesSection = CardService.newCardSection()
  filesSection.setHeader("Selected Files");

 // New Code starts here 

// # 1
// Create new array to hold selected files data
  let selectedSheets = [];

// #2
// Fetch selected files data from drive through event objects
  if (e.drive.selectedItems.length > 0) {

    // Selected spreadsheets
// #3
// Among the selected items we'll be selecting only spreadsheets and push them to selected sheets
    e.drive.selectedItems.forEach(item => {
      if (item.mimeType === "application/vnd.google-apps.spreadsheet")
        selectedSheets.push(item)
    }
    );
  }

  // Create a counter to count the number of widgets added
// #4
// COunter is required to prevent error when pushing the file names into UI incase array is empty
  let widgetCounter = 0;

  for (let i = 0; i < selectedSheets.length; i++) {
    // #5
    // Create decorated text with selected files and 
    // add the decorated text to the card section
    filesSection.addWidget(CardService.newDecoratedText()
      //.setText(selectedSheets[i].title)
      .setText(e.drive.selectedItems[0].title)

    );

 // Increase widget counter per loop
 // #4
    widgetCounter += 1;
  }

  // #6
  // Add files as widgets only if widgetCounter is 1+
  //  It prevent error in case only non-spreadsheet files are selected 
  if (widgetCounter >= 1) {
    card.addSection(filesSection)
 }

  // Create Another card that has files list 
  return card.build();
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Здесь (см. код для нумерации, такой как № 1),

  1. Создан массив для хранения данных о выбранных элементах.
  2. Использовал управляющий объект события для получения данных о выбранных файлах.
  3. Среди выбранных элементов мы отфильтровали только электронные таблицы, используя mimeType.
  4. Мы создали счетчик для использования в качестве условия при добавлении файлов в качестве виджетов на карту, чтобы предотвратить ошибки.
  5. Создал украшенный текст а виджеткоторый будет содержать имена файлов каждого файла.
  6. Теперь, наконец, добавил весь раздел файлов в сборщик карт.

Создание действий с помощью кнопки

В Карте интерактивность возможна с помощью действия. Кроме того, проверьте это образец кода. Не забудьте добавить указанную там область действия, чтобы управлять областью действия в файле манифеста.

Давайте добавим кнопки под разделом файлов. Эта кнопка соберет выбранные файлы и передаст их на другую карту, которую мы построим позже. Чтобы не усложнять, я разобью код на более мелкие разделы.


1. Создайте пользовательский интерфейс кнопки с действием

  let nxtButtonSection = CardService.newCardSection();
  let nxtButtonAction = CardService.newAction()
    .setFunctionName("handleNextButtonClick");
Войти в полноэкранный режим

Выйти из полноэкранного режима

Вы заметили, что ручкаNextButtonClick была назначена как функция, которая будет запускаться при нажатии кнопки. Он будет обрабатывать навигацию и указывает на следующую карту. Мы создадим эту функцию позже.


2. Назначьте параметры для передачи.

 // We'll pass only pass ids of files to the next card so that we can fetch them there with id
// #1
  let selectedSheetsIDAsStr = selectedSheets.map(item => item.id).join();

// pass the values as params
// #2
  nxtButtonAction.setParameters({
    "nextCard": "nextCard",
    "selectedSheetsIDAsStr": selectedSheetsIDAsStr,
  });

// add button to the button set 
// #3
  let nxtButton = CardService.newTextButton().setText("Next").setOnClickAction(nxtButtonAction);
  let nxtButtonSet = CardService.newButtonSet().addButton(nxtButton);
Войти в полноэкранный режим

Выйти из полноэкранного режима

В карточке параметры нужно передавать через действие с установить параметры метод как объекты (# 2). Важно помнить, что и ключи, и значения должны быть строковыми.(отсюда №1). Кнопки могут быть добавлены как набор кнопок в карточке (#3).

Вы заметили, что следующая карта был назначен в качестве параметра. Это потому, что функция handleNextButtonClick является общей функцией, которая принимает имя карты в качестве параметра, а не жестко кодирует. Таким образом, он будет более эффективным в долгосрочной перспективе.


Добавить кнопку на карточку

//  It prevent error in case only non-spreadsheet files are selected 
  if (widgetCounter >= 1) {
    card.addSection(filesSection)

    // new line
    nxtButtonSection.addWidget(nxtButtonSet);
    card.addSection(nxtButtonSection);
  }
Войти в полноэкранный режим

Выйти из полноэкранного режима


Карточная навигация

Из того, что я понял карточная навигация, короче говоря, принимает список карт как стек. Новая карта для перехода добавляется в верхнюю часть стопки, а извлекается из стопки, чтобы вернуться к предыдущей.

Давайте создадим новый файл, я назову его помощникидобавьте следующие инструкции.

помощники

/* This is a greneral nav function
You use it with card action and as a response, it will supply card functions from cardsInventory */
let handleNextButtonClick = (e) => {

// #1
// Extract string nextCard to pass it as key in cards inventory obj
  let nxtCard = cardsInventory[e.commonEventObject.parameters.nextCard];

  // #2
  // Convert String into List of files selected by the user
  let selectFilesIdList = e.commonEventObject.parameters['selectedSheetsIDAsStr'].split(",");

// #3
// use actionResponse to create a navigation route to the next card
  let nxtActionResponse = CardService.newActionResponseBuilder()
    .setNavigation(CardService.newNavigation().pushCard(nxtCard(selectFilesIdList))) // #4, Passing the mastersheet with params
    .setStateChanged(true)
    .build();

  return nxtActionResponse;
}


/**
 *  Create a dictionary that
 is consist of cards for navigation with appropriate keys  
 */

var cardsInventory = {
  'nextCard': nextCard
}


Войти в полноэкранный режим

Выйти из полноэкранного режима

Давайте сначала поговорим о картыИнвентарь объект. Если вы помните, мы передали параметр следующая карта ранее как строка в itemSelectedCard функция. Эта nextCard — это функция, которую мы создадим следующей. Но дело в том, что вы не можете передать строку и использовать ее для ссылки на переменную (проверьте № 1 в коде). Итак, мы создаем словарь, который будет сопоставлять соответствующие клавиши с функциями для навигации.

Внутри функции handleNextButtonClick:

  1. Извлеките строку, которая является ключом к объекту cardInventory, чтобы выбрать правильную карту для вызова. мы используем События Комментарий Объект для извлечения параметров, переданных ранее.
  2. Строки, которые были переданы как идентификаторы выбранных файлов, мы снова конвертируем в массив.
  3. NewActionResponseBuilder, SetNavigation, NewNavigation и PushCard комбинированные используются для установки нового дорожка на выбранную нами карту.
  4. Здесь мы передаем список идентификаторов в качестве параметров.


Следующая карта для навигации

Мы создадим очень простую карточку, которой будет достаточно, чтобы отобразить список идентификаторов, чтобы мы знали, что наш код работает.

Во-первых, давайте создадим новый файл следующая_карта.

var nextCard = function (lst) {

  let cardService = CardService.newCardBuilder().setHeader(CardService.newCardHeader().setTitle("Select Master Sheet To Update"));

  let filesSection = CardService.newCardSection();

  filesSection.setHeader("Selected Files");

  let widgetCounter = 0;

  let selectedFilesList = [...lst];

  selectedFilesList.forEach(id => {
    filesSection.addWidget(CardService.newDecoratedText()
      .setText(id));
    widgetCounter += 1;
  });

  if (widgetCounter >= 1) {
    cardService.addSection(filesSection);
  }


  return cardService.build();
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Единственное новое, на что здесь следует обратить внимание, это то, что я не использую синтаксис es6 для объявления функции. Это потому, что его использование вызвало проблему с областью действия и ошибку, функция не определена. Поэтому я пошел в старую школу с был.


Опубликовать надстройку в GCP для тестирования

Чтобы опубликовать дополнение к GCP, следуйте этим двум инструкциям здесь.

  1. Создать стандарт проект GCP.
  2. Интегрировать проект с проект скрипта приложений.


Окончательный код

карты

var itemSelectedCard = (e) => {

  // Initial UI
  let card = CardService.newCardBuilder().setHeader(CardService.newCardHeader().setTitle("Select Sheets Update Master Sheet"));
  let filesSection = CardService.newCardSection()
  filesSection.setHeader("Selected Files");

  let nxtButtonSection = CardService.newCardSection();
  let nxtButtonAction = CardService.newAction()
    .setFunctionName("handleNextButtonClick");
  let selectedSheets = [];

  if (e.drive.selectedItems.length > 0) {
    // hostApp,clientPlatform,drive,commonEventObject
    // Selected spreadsheets
    e.drive.selectedItems.forEach(item => {
      if (item.mimeType === "application/vnd.google-apps.spreadsheet")
        selectedSheets.push(item)
    }
    );
  }

  // Create a counter to count number of widgets added
  let widgetCounter = 0;

  for (let i = 0; i < selectedSheets.length; i++) {
    // Create decorated text with selected files and 
    // add the decorated text to card section
    filesSection.addWidget(CardService.newDecoratedText()
      //.setText(selectedSheets[i].title)
      .setText(e.drive.selectedItems[0].title)

    );
    widgetCounter += 1;
  }


  // Change list of  selected sheet's id  as string to pass to next card 
  let selectedSheetsIDAsStr = selectedSheets.map(item => item.id).join();

  nxtButtonAction.setParameters({
    "nextCard": "nextCard",
    "selectedSheetsIDAsStr": selectedSheetsIDAsStr,
  });

  let nxtButton = CardService.newTextButton().setText("Next").setOnClickAction(nxtButtonAction);
  let nxtButtonSet = CardService.newButtonSet().addButton(nxtButton);


  // Add files and button section only if the widgets are present
  //  It prevent error in case only non-spreadsheet files are selected 
  if (widgetCounter >= 1) {
    card.addSection(filesSection)

    nxtButtonSection.addWidget(nxtButtonSet);
    card.addSection(nxtButtonSection);
  }

  // Create Another card that has files list 
  return card.build();
}

Войти в полноэкранный режим

Выйти из полноэкранного режима

помощники

/* THis is a greneral nav function
You use it with card action and as reponse it will supply card functions from cardsInventory */
let handleNextButtonClick = (e) => {

  let nextCard = cardsInventory[e.commonEventObject.parameters.nextCard];
  console.log(nextCard)

  // Convert String into List
  let selectFilesIdList = e.commonEventObject.parameters['selectedSheetsIDAsStr'].split(",");

  let nxtActionResponse = CardService.newActionResponseBuilder()
    .setNavigation(CardService.newNavigation().pushCard(nextCard(selectFilesIdList)))
    .setStateChanged(true)
    .build();

  return nxtActionResponse;
}


/**
 *  Create a dictionary that
 is consist of cards for navigation with appropriate keys  
 */

var cardsInventory = {
  'nextCard': nextCard
}

Войти в полноэкранный режим

Выйти из полноэкранного режима

Онлайн-зал кодирования


Резюме

Хорошо, давайте вспомним, что мы делали в проекте.

  1. Определены файлы appscrits.json с соответствующими областями действия и триггерами, необходимыми для надстройки Drive.
  2. Создан простой интерфейс карты для взаимодействия с пользователями.
  3. Извлечены выбранные файлы с диска с помощью скрипта приложений.
  4. Используемые наборы действий и кнопок позволяют пользователям взаимодействовать с пользовательским интерфейсом нашей карты.
  5. Создана простая логика навигации для перемещения между двумя карточками.


Покажите некоторую поддержку

Это Нибеш Хадка из салона кодирования Хадки. Найдите другие мои блоги в Google Apps Scripts здесь. Я владелец салона кодирования Хадки. Мы делаем веб-сайты, мобильные приложения, надстройки Google и ценные технические блоги. Наймите нас! Ставьте лайки, делитесь новостями и подписывайтесь на нашу рассылку.

Наймите нас