1. Введение
В этом практическом занятии вы создадите интерактивный портал быстрой поддержки , напрямую взаимодействующий с Google Workspace Studio. Вы научитесь создавать как пользовательский начальный шаг, так и пользовательский шаг действия, которые можно мгновенно протестировать без использования какой-либо сторонней инфраструктуры.
Мы воспользуемся Google Apps Script для создания:
- Веб-приложение с удобным интерфейсом для ручной отправки запросов в службу поддержки.
- Пользовательский стартовый шаблон , который перехватывает отправленные веб-приложения и запускает рабочий процесс Workspace Studio.
- Пользовательский шаг , который анализирует описание входящего запроса для определения уровня срочности («Высокий» или «Нормальный»).
Что вы узнаете
- Как настроить начальные этапы и шаги в манифесте файла
appsscript.json. - Как сформировать
notifyUriв процессе регистрации стартового объекта. - Как программно запустить процесс Workspace Studio из внешнего кода с помощью
UrlFetchApp. - Как создавать выходные переменные в пользовательских шагах для передачи данных дальше по потоку.
Предварительные требования
- Учетная запись Google Workspace с включенной функцией Google Workspace Studio.
- Параметр «Разрешить неопубликованные (тестовые) пользовательские шаги» должен быть включен в консоли администратора вашего домена (в разделе Приложения > Google Workspace > Workspace Studio > Настройки пользовательских шагов ).
- Знание Google Apps Script.
2. Настройка проекта Apps Script
Для начала создадим новый проект Apps Script для размещения нашего кода:
- Перейдите на сайт script.google.com и нажмите «Новый проект» .
- Назовите проект «Портал быстрой поддержки» .
- Нажмите
Настройки проекта находятся на левой боковой панели.
- Установите флажок, чтобы отображать файл манифеста appsscript.json в редакторе .
- Вернуться к
Режим редактора .
Привяжите стандартный проект Google Cloud.
По умолчанию проекты Apps Script связаны со скрытым проектом Google Cloud по умолчанию. Чтобы вызвать API Google Workspace Studio и избежать ошибок PERMISSION_DENIED , необходимо переключить ваш скрипт на стандартный проект Cloud, включить API и правильно настроить платформу аутентификации Google.
- Выберите или создайте проект: перейдите в консоль Google Cloud и используйте выпадающее меню проектов в верхней части страницы, чтобы выбрать существующий проект или создать новый.
- Включите API: После того, как выбранный вами проект станет активен на верхней панели, откройте процесс включения API , нажмите «Далее» и «Включить» для API Workspace Studio .
- Настройка фирменной символики OAuth: Откройте страницу фирменной символики платформы Google Auth .
- Если появится запрос, нажмите «Начать» . (Если настройка уже выполнена, перейдите к шагу 4).
- В разделе «Информация о приложении» введите название приложения и адрес электронной почты службы поддержки пользователей. Нажмите «Далее» .
- В разделе «Аудитория» выберите «Внутренняя» (или «Внешняя» , если «Внутренняя» недоступна) и нажмите «Далее» .
- Укажите контактную информацию, согласитесь с политикой обработки данных и нажмите «Создать» .
- Настройка доступа к данным: Откройте страницу «Доступ к данным» и нажмите «Добавить или удалить области доступа» .
- В разделе « Добавить области действия вручную» вставьте
https://www.googleapis.com/auth/workspace.studio.trigger. - Нажмите «Добавить в таблицу» , затем «Обновить» и, наконец, нажмите «Сохранить» внизу страницы.
- В разделе « Добавить области действия вручную» вставьте
- Перейдите в раздел IAM & Admin > Settings (или на панель управления Cloud Console) и скопируйте номер проекта .
- Вернитесь к своему проекту Apps Script и нажмите
Настройки проекта находятся на левой боковой панели.
- В разделе «Проект Google Cloud Platform (GCP)» нажмите «Изменить проект» .
- Введите скопированный номер проекта GCP и нажмите «Установить проект» .
Настройте манифест
Откройте открывшийся файл appsscript.json . Замените его содержимое приведенным ниже кодом. Этот манифест явно перечисляет необходимые нам области действия OAuth и определяет наш стартовый процесс как workflowTrigger , а действие как workflowAction в блоке studio.flows.workflowElements .
{
"timeZone": "America/Los_Angeles",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"webapp": {
"executeAs": "USER_ACCESSING",
"access": "MYSELF"
},
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/workspace.studio.trigger",
"https://www.googleapis.com/auth/script.storage",
"https://www.googleapis.com/auth/script.locale"
],
"urlFetchWhitelist": [
"https://workspacestudio.googleapis.com/"
],
"addOns": {
"common": {
"name": "Support Extension",
"logoUrl": "https://www.gstatic.com/images/branding/productlogos/buganizer/v1/192px.svg",
"useLocaleFromApp": true
},
"studio": {
"flows": {
"workflowElements": [
{
"id": "supportTicketTrigger",
"state": "ACTIVE",
"name": "New Support Ticket",
"description": "Fires when someone submits a ticket via the Web App.",
"workflowTrigger": {
"inputs": [],
"outputs": [
{
"id": "ticketTitle",
"description": "The title of the ticket",
"cardinality": "SINGLE",
"dataType": { "basicType": "STRING" }
},
{
"id": "ticketDescription",
"description": "The full description of the issue",
"cardinality": "SINGLE",
"dataType": { "basicType": "STRING" }
}
],
"onConfigFunction": "onConfigTrigger",
"onManageFunction": "onManageTrigger"
}
},
{
"id": "urgencyDetectorStep",
"state": "ACTIVE",
"name": "Detect Urgency",
"description": "Scans the ticket description to detect High or Normal urgency.",
"workflowAction": {
"inputs": [
{
"id": "ticketDescription",
"description": "The ticket description",
"cardinality": "SINGLE",
"dataType": { "basicType": "STRING" }
}
],
"outputs": [
{
"id": "urgencyLevel",
"description": "The urgency High/Normal",
"cardinality": "SINGLE",
"dataType": { "basicType": "STRING" }
}
],
"onConfigFunction": "onConfigUrgency",
"onExecuteFunction": "onExecuteUrgency"
}
}
]
}
}
}
}
3. Создайте пользовательский интерфейс веб-приложения.
Чтобы предоставить наглядный и проверяемый способ запуска нашего стартового приложения без использования терминальных инструментов или сторонних веб-хуков, мы создадим веб-приложение на Apps Script.
В редакторе Apps Script рядом с пунктом «Файлы» нажмите Добавьте файл и выберите HTML . Назовите его
index.html (расширение .html добавляется автоматически).
Вставьте следующий упрощенный код пользовательского интерфейса:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
body { font-family: Arial, sans-serif; padding: 20px; max-width: 500px; margin: auto; }
label { font-weight: bold; display: block; margin-top: 15px; }
input, textarea { width: 100%; margin-top: 5px; padding: 10px; box-sizing: border-box; }
button { background-color: #1a73e8; color: white; border: none; padding: 10px 15px; margin-top: 15px; font-weight: bold; cursor: pointer; border-radius: 4px; }
button:hover { background-color: #1557b0; }
#status { margin-top: 15px; color: green; font-weight: bold; }
</style>
</head>
<body>
<h2>Support Quick Portal</h2>
<p>Submit your issue below to trigger the Workspace Studio flow.</p>
<label for="title">Ticket Title</label>
<input type="text" id="title" placeholder="e.g. Broken monitor">
<label for="description">Issue Description</label>
<textarea id="description" rows="4" placeholder="Explain your issue (use words like 'urgent' to test the step!)..."></textarea>
<button onclick="submitTicket()">Submit Ticket</button>
<div id="status"></div>
<script>
function submitTicket() {
const title = document.getElementById('title').value;
const description = document.getElementById('description').value;
const statusEl = document.getElementById('status');
if (!title || !description) {
statusEl.style.color = "red";
statusEl.innerText = "Please fill out both fields.";
return;
}
statusEl.style.color = "green";
statusEl.innerText = "Submitting ticket...";
google.script.run
.withSuccessHandler(function(response) {
statusEl.innerText = response;
})
.withFailureHandler(function(error) {
statusEl.style.color = 'red';
statusEl.innerText = 'Error: ' + error.message;
})
.submitTicketToStudio(title, description);
}
</script>
</body>
</html>
4. Создайте скрипты для бэкэнда.
Теперь давайте всё это объединим. Чтобы код оставался читаемым, мы разделим логику веб-приложения, логику стартового шаблона и логику шага действия на три разных скриптовых файла.
WebApp.gs
Переименуйте стандартный файл Code.gs в редакторе в WebApp.gs , удалите шаблон myFunction и скопируйте и вставьте в него следующий блок кода. Этот файл отвечает за размещение веб-приложения:
/** --- WEB APP HOSTING --- **/
/**
* Serves the HTML UI when users visit the web app URL.
*/
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setTitle('Support Quick Portal')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/**
* Called by the Web App form. It calls the Workspace Studio API.
*/
function submitTicketToStudio(title, description) {
const props = PropertiesService.getUserProperties();
const notifyUri = props.getProperty('notifyUri');
const triggerId = props.getProperty('triggerId');
if (!notifyUri || !triggerId) {
throw new Error('Trigger URL missing! Make sure the flow is enabled in Workspace Studio.');
}
// Use ScriptApp.getOAuthToken() (requires the workspace.studio.trigger scope in manifest)
const token = ScriptApp.getOAuthToken();
const requestId = Utilities.getUuid();
// Package our outputs mapped in appsscript.json
const payload = {
"name": "triggers/" + triggerId,
"outputs": {
"ticketTitle": { "stringValues": [title] },
"ticketDescription": { "stringValues": [description] }
},
"requestId": requestId
};
const options = {
"method": "POST",
"contentType": "application/json",
"headers": { "Authorization": "Bearer " + token },
"payload": JSON.stringify(payload),
"muteHttpExceptions": true
};
// Fire!
const response = UrlFetchApp.fetch(notifyUri, options);
if (response.getResponseCode() !== 200) {
console.error(response.getContentText());
throw new Error('Workspace Studio API Error: ' + response.getResponseCode());
}
return 'Ticket successfully routed to Workspace Studio!';
}
Starter.gs
Далее наведите курсор на «Файлы» и нажмите. Добавьте файл , выберите «Скрипт» и назовите его
Starter.gs . Скопируйте и вставьте в него приведенный ниже блок. Этот файл отвечает за настройку Starter и управление жизненным циклом Workspace Studio:
/** --- STARTER LOGIC --- **/
/**
* Workspace Studio calls this to display the config UI when the user adds the starter.
* We just return a static message since there are no properties to configure.
*/
function onConfigTrigger() {
const section = CardService.newCardSection()
.setHeader("Configure Web App Starter")
.addWidget(CardService.newTextParagraph().setText("Ready to go! Once you enable this flow, deploy your Apps Script project as a Web App to submit tickets."));
return CardService.newCardBuilder().addSection(section).build();
}
/**
* Workspace Studio posts data here to manage the lifecycle (enable/disable the trigger).
* Critically, we must construct or save the `notifyUri` and `triggerId` to call it later.
*/
function onManageTrigger(event) {
const triggerCreation = event.workflow.triggerCreation;
const triggerDeletion = event.workflow.triggerDeletion;
const props = PropertiesService.getUserProperties();
if (triggerCreation) {
// Save the unique URL and ID when the flow is enabled
// Note: notifyUri might be omitted, so fallback to constructing it dynamically
const notifyUri = triggerCreation.notifyUri || `https://workspacestudio.googleapis.com/v1/triggers/${triggerCreation.triggerId}:fire`;
props.setProperty('notifyUri', notifyUri);
props.setProperty('triggerId', triggerCreation.triggerId);
} else if (triggerDeletion) {
// Cleanup if the user deletes the flow
props.deleteProperty('notifyUri');
props.deleteProperty('triggerId');
}
}
Action.gs
Далее наведите курсор на «Файлы» и нажмите. Добавьте файл , выберите «Скрипт» и назовите его
Action.gs . Скопируйте и вставьте в него логику шага «Срочность», приведенную ниже:
/** --- ACTION STEP LOGIC --- **/
/**
* Workspace Studio configuration card for the Step.
* We prompt the user to bind a variable to our "ticketDescription" input.
*/
function onConfigUrgency() {
const input = CardService.newTextInput()
.setFieldName("ticketDescription")
.setTitle("Source Description")
.setHint('Select the description variable outputted by the starter')
.setHostAppDataSource(
CardService.newHostAppDataSource().setWorkflowDataSource(CardService.newWorkflowDataSource().setIncludeVariables(true))
);
const section = CardService.newCardSection()
.setHeader("Urgency Detector Step")
.addWidget(input);
return CardService.newCardBuilder().addSection(section).build();
}
/**
* The synchronous logic executed during the Step.
*/
function onExecuteUrgency(event) {
// Read mapped inputs
let description = event.workflow.actionInvocation.inputs["ticketDescription"].stringValues[0];
if (!description) description = "";
const urgentKeywords = ['urgent', 'crash', 'broken', 'down', 'fire'];
let urgencyLevel = 'Normal';
if (urgentKeywords.some(keyword => description.toLowerCase().includes(keyword))) {
urgencyLevel = 'High';
}
// Package outputs correctly
const variableDataMap = {
"urgencyLevel": AddOnsResponseService.newVariableData().addStringValue(urgencyLevel)
};
return outputVariables(variableDataMap);
}
/**
* Helper strictly enforcing the expected Step object return type.
*/
function outputVariables(variableDataMap) {
const workflowAction = AddOnsResponseService.newReturnOutputVariablesAction()
.setVariableDataMap(variableDataMap);
const hostAppAction = AddOnsResponseService.newHostAppAction()
.setWorkflowAction(workflowAction);
return AddOnsResponseService.newRenderActionBuilder()
.setHostAppAction(hostAppAction)
.build();
}
5. Развертывание и тестирование
После написания кода давайте развернем проект и настроим его.
Шаг 1: Повторно авторизуйте скрипт.
Поскольку вы подключили новый стандартный проект Google Cloud, вам необходимо явно разрешить области действия скрипта (например, script.external_request , используемый UrlFetchApp ) для нового проекта.
- В редакторе Apps Script выберите файл
WebApp.gsв папке Files , затем выберите функциюdoGetиз выпадающего списка на верхней панели инструментов. - Нажмите «Выполнить» .
- Появится сообщение «Требуется авторизация». Нажмите «Проверить разрешения ».
- Выберите свою учетную запись и авторизуйте скрипт. Если вы видите предупреждение «Непроверенное приложение», нажмите «Дополнительно» -> «Перейти на портал быстрой поддержки», чтобы обойти это предупреждение.
- Дождитесь появления в журнале выполнения сообщения «Выполнение завершено» , что подтверждает полную авторизацию скрипта.
Шаг 2: Тестирование расширения и веб-приложения
Поскольку в вашем appsscript.json определены как дополнение, так и веб-приложение, вы можете настроить оба варианта одновременно.
- В правом верхнем углу окна Apps Script нажмите «Развернуть» > «Проверить развертывания» .
- Рядом с пунктом «Выберите тип» нажмите
Включите типы развертывания и убедитесь, что установлен флажок «Дополнения Google Workspace» , затем нажмите «Установить» .
- Нажмите
Снова включите типы развертывания , убедитесь, что отмечено «Веб-приложение» , и скопируйте URL-адрес (он будет заканчиваться на
/dev). Это URL-адрес веб-приложения «Быстрый портал поддержки» , которое вы создали. - Нажмите «Готово» . Возможно, вам потребуется обновить страницу в браузере, прежде чем Workspace Studio зарегистрирует надстройку.
Шаг 3: Настройка рабочего процесса Studio Flow
- Откройте Google Workspace Studio по адресу studio.workspace.google.com .
- Нажмите
Добавьте инструмент слева и выберите «Поток» .
- Чтобы настроить стартовый пакет, нажмите «Выбрать стартовый пакет» , затем выберите установленное расширение поддержки > «Создать заявку в службу поддержки ». Если появится сообщение «Требуется разрешение», нажмите «Предоставить разрешение» , чтобы разрешить надстройке доступ к вашим данным.
- Далее, в разделе «Действия» нажмите «Выбрать шаг» , прокрутите до пункта «Расширение поддержки» и выберите шаг «Определение срочности» .
- В разделе «Описание источника» нажмите
Переменные и выберите Шаг 1: Создать заявку в службу поддержки > Полное описание проблемы (
ticketDescription). - Нажмите «Выбрать шаг» еще раз и выберите встроенный шаг, например, Gmail > Отправить электронное письмо или Чат > Уведомить меня в чате .
- Если вы выбрали Gmail:
- Кому: Укажите свой адрес электронной почты.
- Тема:
ticketTitle-urgencyLevel - Сообщение:
ticketDescription
- Если вы выбрали чат:
- Сообщение: Заявка
ticketTitlepriority isurgencyLevel.ticketDescription
- Сообщение: Заявка
- Если вы выбрали Gmail:
- Включите рабочий процесс. Если появится запрос на переименование потока , введите имя, например,
Support Ticket Router, и сохраните. Это запустит жизненный циклonManageTrigger, сохранивnotifyUri.
Шаг 4: Запустите симуляцию
- Откройте в новой вкладке браузера URL-адрес веб-приложения, скопированный вами ранее на шаге 2 этой страницы (он заканчивается на /dev).
- Заполните форму. Убедитесь, что в описании присутствует ключевое слово-триггер (например, «срочно» или «сбой»).
- Нажмите «Отправить» . Дождитесь сообщения «Заявка успешно обработана».
- Проверьте журнал активности Workspace Studio, свою почту Gmail или Google Chat (в зависимости от выбранного действия). Вы должны увидеть сообщение или электронное письмо с пометкой «Высокая срочность» , интегрированное с помощью ваших пользовательских элементов Apps Script.
6. Уборка
Чтобы избежать захламления рабочего пространства и учетной записи Google Cloud, вы можете очистить ресурсы, созданные вами в ходе этого практического занятия.
- Удалите рабочий процесс Workspace Studio:
- Откройте studio.workspace.google.com .
- Найдите схему
Support Ticket Router. - Нажмите на меню с тремя точками рядом с ним и выберите «Удалить» .
- Удалите проект Apps Script:
- Перейдите на script.google.com .
- Найдите проект
Support Quick Portal. - Нажмите на меню с тремя точками и выберите «Удалить» .
- Закрытие проекта Google Cloud:
- Перейдите в консоль Google Cloud .
- Убедитесь, что в верхнем выпадающем списке выбран ваш новый проект.
- Перейдите в раздел IAM и администрирование > Настройки и нажмите «Выключить» .
7. Заключение
Вы успешно создали полноценную экосистему для пользовательских расширений Google Workspace Studio, не прибегая к услугам сторонних подрядчиков.
Что мы обсуждали:
- Использование
workflowTriggerсовместно сonManageFunctionпозволяет корректно фиксировать и обрабатывать события жизненного цикла Google. - Аутентификация запросов к бэкэнду с использованием
ScriptApp.getOAuthToken()по отношению к конечным точкам APIworkspacestudio.googleapis.com. - Использование
workflowActionдля синхронной обработки входных переменных и генерации последующих выходных данных.
Теперь вы можете масштабировать эти принципы для интеграции с реальными SaaS-платформами, такими как Jira, Salesforce или Zendesk, изменив источник срабатывания вашего веб-приложения (или входящего веб-хука).