Tworzenie niestandardowych kroków inicjujących i działań w Workspace Studio

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ć notifyUri podczas 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:

  1. Otwórz script.google.com i kliknij Nowy projekt.
  2. Nazwij projekt Support Quick Portal.
  3. Na pasku bocznym po lewej stronie kliknij Ustawienia projektu Ustawienia projektu.
  4. Zaznacz pole Show appsscript.json manifest file in editor (Wyświetl plik manifestu appsscript.json w edytorze).
  5. Wróć do widoku Edytujący Edytor.

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.

  1. 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.
  2. 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.
  3. Skonfiguruj markę OAuth: otwórz stronę marki platformy uwierzytelniania Google.
    1. W razie potrzeby kliknij Rozpocznij. (Jeśli jest już skonfigurowany, przejdź do kroku 4).
    2. W sekcji Informacje o aplikacji wpisz nazwę aplikacji i adres e-mail pomocy dla użytkowników. Kliknij Dalej.
    3. W sekcji Odbiorcy wybierz Wewnętrzny (lub Zewnętrzny, jeśli opcja Wewnętrzny jest niedostępna) i kliknij Dalej.
    4. Podaj informacje kontaktowe, zaakceptuj zasady dotyczące danych i kliknij Utwórz.
  4. Skonfiguruj dostęp do danych: otwórz stronę Dostęp do danych i kliknij Dodaj lub usuń zakresy.
    1. W sekcji Ręczne dodawanie zakresów wklej https://www.googleapis.com/auth/workspace.studio.trigger.
    2. Kliknij Dodaj do tabeli, a potem Aktualizuj. Na koniec kliknij Zapisz u dołu strony.
  5. Otwórz Administracja > Ustawienia (lub panel konsoli Google Cloud) i skopiuj numer projektu.
  6. Wróć do projektu Apps Script i na pasku bocznym po lewej stronie kliknij Ustawienia projektu Ustawienia projektu.
  7. W sekcji Projekt Google Cloud Platform (GCP) kliknij Zmień projekt.
  8. 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 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 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 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.

  1. W edytorze skryptów Apps Script kliknij WebApp.gs w sekcji Pliki, a następnie wybierz funkcję doGet z menu na pasku narzędzi u góry.
  2. Kliknij Wykonaj.
  3. Wyświetli się prośba o autoryzację. Kliknij Przejrzyj uprawnienia.
  4. Wybierz konto i autoryzuj skrypt. Jeśli zobaczysz ostrzeżenie „Niezweryfikowana aplikacja”, kliknij Zaawansowane –> Otwórz Portal szybkiej pomocy, aby je pominąć.
  5. 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.

  1. W prawym górnym rogu Apps Script kliknij Wdróż > Testuj wdrożenia.
  2. Obok pozycji Wybierz typ kliknij Włączanie typów wdrożenia Włącz typy wdrożeń i upewnij się, że pole Dodatki do Google Workspace jest zaznaczone. Następnie kliknij Zainstaluj.
  3. Ponownie kliknij Włączanie typów wdrożenia 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.
  4. Kliknij Gotowe. Zanim Workspace Studio zarejestruje dodatek, może być konieczne odświeżenie przeglądarki.

Krok 3. Skonfiguruj Studio Flow

  1. Otwórz Google Workspace Studio na stronie studio.workspace.google.com.
  2. Po lewej stronie kliknij Dodaj narzędzie Dodaj narzędzie i wybierz Przepływ.
  3. 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.
  4. Następnie w sekcji Działania kliknij Wybierz krok, przewiń do opcji „Rozszerzenie pomocy” i wybierz krok Wykryj pilność.
  5. W sekcji Opis źródła kliknij Dodaj Zmienne i wybierz Krok 1. Nowe zgłoszenie > Pełny opis problemu (ticketDescription).
  6. 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 ticketTitle to urgencyLevel
      • Wiadomość: ticketDescription
    • Jeśli wybierzesz Chat:
      • Wiadomość: priorytet zgłoszenia ticketTitle to urgencyLevel. ticketDescription
  7. 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 życia onManageTrigger i zapisanie notifyUri.

Krok 4. Uruchom symulację

  1. 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”).
  2. Wypełnij formularz. Upewnij się, że w opisie znajduje się słowo kluczowe wywołujące alert (np. „pilne” lub „awaria”).
  3. Kliknij Prześlij. Poczekaj na komunikat „Ticket successfully routed” (Zgłoszenie zostało przekazane).
  4. 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.

  1. 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ń.
  2. Usuń projekt Apps Script:
    • Wejdź na script.google.com.
    • Znajdź projekt Support Quick Portal.
    • Kliknij menu z 3 kropkami i wybierz Usuń.
  3. 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 workflowTrigger razem z onManageFunction do prawidłowego rejestrowania i obsługi zdarzeń cyklu życia Google.
  • Uwierzytelnianie żądań backendu za pomocą ScriptApp.getOAuthToken() w punktach końcowych interfejsu workspacestudio.googleapis.com API.
  • Używanie funkcji workflowAction do 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).