1. Wprowadzenie
W tym ćwiczeniu utworzysz interaktywny portal szybkiej pomocy, który bezpośrednio współpracuje z Google Workspace Studio. Dowiesz się, jak utworzyć niestandardowy krok początkowy i niestandardowy krok działania, które można od razu przetestować bez korzystania z infrastruktury zewnętrznej.
Za pomocą Google Apps Script utworzymy:
- Aplikacja internetowa z eleganckim formularzem, za pomocą którego użytkownicy mogą ręcznie przesyłać zgłoszenia do pomocy.
- Niestandardowy moduł uruchamiający, który rejestruje przesłane zgłoszenia w aplikacji internetowej i uruchamia automatyzację w Workspace Studio.
- Krok niestandardowy, który analizuje opis przychodzącego zgłoszenia, aby określić poziom pilności („Wysoki” lub „Normalny”).
Czego się nauczysz
- Jak skonfigurować polecenia inicjujące i kroki w pliku manifestu
appsscript.json. - Jak utworzyć
notifyUripodczas cyklu życia rejestracji początkowej. - Jak programowo wywołać automatyzację Workspace Studio z kodu zewnętrznego za pomocą
UrlFetchApp. - Jak tworzyć zmienne wyjściowe w krokach niestandardowych, aby przekazywać dane do dalszych kroków.
Wymagania wstępne
- konto Google Workspace z włączoną usługą Google Workspace Studio;
- Ustawienie Zezwalaj na nieopublikowane (testowe) niestandardowe kroki musi być włączone w konsoli administracyjnej domeny (w sekcji Aplikacje > Google Workspace > Workspace Studio > ustawienia niestandardowych kroków).
- Znajomość Google Apps Script.
2. Konfigurowanie projektu Apps Script
Najpierw utwórzmy nowy projekt Apps Script, w którym umieścimy kod:
- Otwórz script.google.com i kliknij Nowy projekt.
- Nazwij projekt Support Quick Portal.
- Na pasku bocznym po lewej stronie kliknij
Ustawienia projektu.
- Zaznacz pole Show appsscript.json manifest file in editor (Wyświetl plik manifestu appsscript.json w edytorze).
- Wróć do widoku
Edytor.
Łączenie standardowego projektu Google Cloud
Domyślnie projekty Apps Script są powiązane z ukrytym domyślnym projektem w chmurze Google Cloud. Aby wywołać interfejs Google Workspace Studio API i uniknąć błędów PERMISSION_DENIED, musisz przełączyć skrypt na standardowy projekt w chmurze, włączyć interfejs API i prawidłowo skonfigurować platformę Google Auth.
- Wybierz lub utwórz projekt: otwórz konsolę Google Cloud i użyj menu projektu u góry strony, aby wybrać istniejący projekt lub utworzyć nowy.
- Włącz interfejs API: gdy wybrany projekt będzie aktywny na pasku u góry, otwórz proces włączania interfejsu API i kliknij Dalej oraz Włącz w przypadku Workspace Studio API.
- Skonfiguruj markę OAuth: otwórz stronę marki platformy uwierzytelniania Google.
- W razie potrzeby kliknij Rozpocznij. (Jeśli jest już skonfigurowany, przejdź do kroku 4).
- W sekcji Informacje o aplikacji wpisz nazwę aplikacji i adres e-mail pomocy dla użytkowników. Kliknij Dalej.
- W sekcji Odbiorcy wybierz Wewnętrzny (lub Zewnętrzny, jeśli opcja Wewnętrzny jest niedostępna) i kliknij Dalej.
- Podaj informacje kontaktowe, zaakceptuj zasady dotyczące danych i kliknij Utwórz.
- Skonfiguruj dostęp do danych: otwórz stronę Dostęp do danych i kliknij Dodaj lub usuń zakresy.
- W sekcji Ręczne dodawanie zakresów wklej
https://www.googleapis.com/auth/workspace.studio.trigger. - Kliknij Dodaj do tabeli, a potem Aktualizuj. Na koniec kliknij Zapisz u dołu strony.
- W sekcji Ręczne dodawanie zakresów wklej
- Otwórz Administracja > Ustawienia (lub panel konsoli Google Cloud) i skopiuj numer projektu.
- Wróć do projektu Apps Script i na pasku bocznym po lewej stronie kliknij
Ustawienia projektu.
- W sekcji Projekt Google Cloud Platform (GCP) kliknij Zmień projekt.
- Wpisz skopiowany numer projektu GCP i kliknij Ustaw projekt.
Konfigurowanie pliku manifestu
Otwórz nowo widoczny plik appsscript.json. Zastąp jego zawartość poniższym kodem. W tym manifeście wyraźnie wymieniamy wymagane zakresy OAuth i definiujemy starter jako workflowTrigger oraz action jako workflowAction w bloku 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. Tworzenie interfejsu aplikacji internetowej
Aby zapewnić wizualny i testowalny sposób uruchamiania naszego polecenia inicjującego bez używania narzędzi terminalowych ani webhooków innych firm, utworzymy aplikację internetową Apps Script.
W edytorze skryptów Apps Script obok pozycji Pliki kliknij Dodaj plik i wybierz HTML. Nadaj mu nazwę
index.html (rozszerzenie .html zostanie dodane automatycznie).
Wklej ten uproszczony kod interfejsu:
<!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. Tworzenie skryptów backendu
Teraz połączmy to wszystko. Aby kod był czytelny, podzielimy aplikację internetową, logikę Startera i logikę kroku działania na 3 różne pliki skryptu.
WebApp.gs
Zmień nazwę domyślnego pliku Code.gs w edytorze na WebApp.gs, usuń standardowy kod myFunction, a następnie skopiuj i wklej do niego blok poniżej. Ten plik obsługuje hosting aplikacji internetowej:
/** --- 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
Następnie najedź kursorem na Pliki, kliknij Dodaj plik, wybierz Skrypt i nadaj mu nazwę
Starter.gs. Skopiuj i wklej do niego blok poniżej. Ten plik obsługuje konfigurację polecenia inicjującego i zarządzanie cyklem życia 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
Następnie najedź kursorem na Pliki, kliknij Dodaj plik, wybierz Skrypt i nadaj mu nazwę
Action.gs. Skopiuj i wklej do niego poniższą logikę kroku pilności:
/** --- 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. Wdrażanie i testowanie
Po napisaniu kodu wdróżmy projekt i skonfigurujmy go.
Krok 1. Ponownie autoryzuj skrypt
Ponieważ połączono nowy standardowy projekt w chmurze Google, musisz wyraźnie autoryzować zakresy skryptu (np. script.external_request używane przez UrlFetchApp) w nowym projekcie.
- W edytorze skryptów Apps Script kliknij
WebApp.gsw sekcji Pliki, a następnie wybierz funkcjędoGetz menu na pasku narzędzi u góry. - Kliknij Wykonaj.
- Wyświetli się prośba o autoryzację. Kliknij Przejrzyj uprawnienia.
- Wybierz konto i autoryzuj skrypt. Jeśli zobaczysz ostrzeżenie „Niezweryfikowana aplikacja”, kliknij Zaawansowane –> Otwórz Portal szybkiej pomocy, aby je pominąć.
- Poczekaj, aż w dzienniku wykonania pojawi się komunikat Wykonanie zakończone. Oznacza to, że skrypt ma już pełne uprawnienia.
Krok 2. Przetestuj rozszerzenie i aplikację internetową
Plik appsscript.json definiuje zarówno dodatek, jak i aplikację internetową, więc możesz skonfigurować oba jednocześnie.
- W prawym górnym rogu Apps Script kliknij Wdróż > Testuj wdrożenia.
- Obok pozycji Wybierz typ kliknij
Włącz typy wdrożeń i upewnij się, że pole Dodatki do Google Workspace jest zaznaczone. Następnie kliknij Zainstaluj.
- Ponownie kliknij
Włącz typy wdrożenia, upewnij się, że pole Aplikacja internetowa jest zaznaczone, i skopiuj adres URL (będzie się kończył na
/dev). Jest to adres URL utworzonej przez Ciebie aplikacji internetowej Support Quick Portal. - Kliknij Gotowe. Zanim Workspace Studio zarejestruje dodatek, może być konieczne odświeżenie przeglądarki.
Krok 3. Skonfiguruj Studio Flow
- Otwórz Google Workspace Studio na stronie studio.workspace.google.com.
- Po lewej stronie kliknij
Dodaj narzędzie i wybierz Przepływ.
- Aby skonfigurować Starter, kliknij Wybierz Starter, a następnie wybierz zainstalowane rozszerzenie pomocy > Nowe zgłoszenie. Jeśli pojawi się komunikat „Wymagane uprawnienia”, kliknij Przyznaj uprawnienia, aby umożliwić dodatkowi dostęp do Twoich danych.
- Następnie w sekcji Działania kliknij Wybierz krok, przewiń do opcji „Rozszerzenie pomocy” i wybierz krok Wykryj pilność.
- W sekcji Opis źródła kliknij
Zmienne i wybierz Krok 1. Nowe zgłoszenie > Pełny opis problemu (
ticketDescription). - Ponownie kliknij Wybierz krok i wybierz wbudowany krok, np. Gmail > Wyślij e-maila lub Google Chat > Powiadom mnie w Google Chat.
- Jeśli wybierzesz Gmaila:
- Do: wpisz swój adres e-mail.
- Temat: priorytet zgłoszenia
ticketTitletourgencyLevel - Wiadomość:
ticketDescription
- Jeśli wybierzesz Chat:
- Wiadomość: priorytet zgłoszenia
ticketTitletourgencyLevel.ticketDescription
- Wiadomość: priorytet zgłoszenia
- Jeśli wybierzesz Gmaila:
- Włącz przepływ pracy. Jeśli pojawi się prośba o zmianę nazwy przepływu, wpisz nazwę, np.
Support Ticket Router, i zapisz ją. Spowoduje to uruchomienie cyklu życiaonManageTriggeri zapisanienotifyUri.
Krok 4. Uruchom symulację
- Otwórz adres URL aplikacji internetowej skopiowany wcześniej w kroku 2 na tej stronie w nowej karcie przeglądarki (kończy się on ciągiem „/dev”).
- Wypełnij formularz. Upewnij się, że w opisie znajduje się słowo kluczowe wywołujące alert (np. „pilne” lub „awaria”).
- Kliknij Prześlij. Poczekaj na komunikat „Ticket successfully routed” (Zgłoszenie zostało przekazane).
- Sprawdź dziennik aktywności Workspace Studio, skrzynkę odbiorczą Gmaila lub Google Chat (w zależności od wybranej czynności). Powinien pojawić się komunikat lub e-mail oznaczony jako „Wysoki” priorytet, który jest natywnie zintegrowany przy użyciu niestandardowych elementów Apps Script.
6. Czyszczenie
Aby uniknąć zaśmiecania obszaru roboczego i konta Google Cloud, możesz zwolnić miejsce, usuwając zasoby utworzone podczas tego ćwiczenia.
- Usuń automatyzację Workspace Studio:
- Otwórz studio.workspace.google.com.
- Znajdź swój
Support Ticket Routerrytm. - Kliknij menu z 3 kropkami obok niego i wybierz Usuń.
- Usuń projekt Apps Script:
- Wejdź na script.google.com.
- Znajdź projekt
Support Quick Portal. - Kliknij menu z 3 kropkami i wybierz Usuń.
- Wyłącz projekt Google Cloud:
- Otwórz konsolę Google Cloud.
- Sprawdź, czy w menu u góry wybrany jest nowy projekt.
- Kliknij Administracja > Ustawienia i Wyłącz.
7. Podsumowanie
Udało Ci się stworzyć kompletny ekosystem niestandardowych rozszerzeń Google Workspace Studio bez korzystania z zewnętrznych subskrypcji innych firm.
Omówione zagadnienia:
- Używanie
workflowTriggerrazem zonManageFunctiondo prawidłowego rejestrowania i obsługi zdarzeń cyklu życia Google. - Uwierzytelnianie żądań backendu za pomocą
ScriptApp.getOAuthToken()w punktach końcowych interfejsuworkspacestudio.googleapis.comAPI. - Używanie funkcji
workflowActiondo synchronicznego przetwarzania zmiennych wejściowych i generowania wyjść podrzędnych.
Możesz teraz skalować w poziomie te zasady, aby podłączyć się do prawdziwych platform SaaS, takich jak Jira, Salesforce czy Zendesk, modyfikując miejsce, z którego wywoływana jest aplikacja internetowa (lub przychodzący webhook).