Adaptive Cards

Ten post jest związany z screencastem, który niedawno zrobiłem. Opisuje w szczegółach, w jaki sposób Flow, używany przez to rozwiązanie, jest zbudowany. Życzę przyjemnego oglądania i nauki jednocześnie, jak takie rozwiązanie można wykonać. Ten wpis jest również częścią serii, którą piszę o „Adaptive Cards”.

Screencast

Screencast Adaptive Cards showcase

Rozwiązanie

Rozwiązanie jest zbudowane przy użyciu PowerApps, dając użytkownikom interfejs dla procesu. Wszystkie dane są przechowywane w dwóch encjach, w Common Data Service (CDS). Rozwiązanie korzysta również z Microsoft Teams wraz z Adaptive Cards, jako medium do komunikacji w podejściu Digital Workplace (wszystkie informacje przechowywane w jednym środowisku, zunifikowany user experience) i Microsoft Flow, który obsługuje zatwierdzanie i przetwarzanie danych.

W tym poście skoncentruję się tylko na Microsoft Flow i sposobie jego działania z kartami Adaptive Cards, ponieważ stanowi on rdzeń całego rozwiązania.

Jak został zbudowany Flow

Microsoft Flow posting Adaptive Cards
Microsoft Flow wysyłający Adaptive Cards

Ponieważ aplikacja, jaką zbudowałem, posiada poziom obsługi błędów wyłapujący błędy na poziomie danych, toteż uznałem, że nie ma powodu by po wysłaniu nowego wniosku aplikacja czekała, aż Flow zostanie wykonany. Z tego powodu zdecydowałem się na użycie innego wyzwalacza:zamiast PowerApps użyłem wyzwalacza „When a record is created” (1) z zestawu wyzwalaczy usługi Common Data Service (pamiętaj, że wymaga on licencji P1!).

Dalej (2) pobieram informację o powiązanym rekordzie, który zawiera limity dostępnych dni dla użytkownika, który uruchomił Flow, dla bieżącego roku. W tym celu używam kolumny „lookup” w CDS, budując relację między pojedynczym żądaniem, a informacjami o limitach użytkownika:

Getting related record in CDS using Lookup column
Pobieranie powiązanego rekordu używając kolumny Lookup

Następnym krokiem (3) jest uzyskanie szczegółów wnioskującego i danych menedżera. Wykonuję to za pomocą działań z zestawu akcji „Office 365 Users”:

  • Get user profile (V2)
  • Get manager (V2)

Przygotowywanie i przydzielanie zadania

Teraz zaczyna się magia 🙂 W scope (4) Flow wykonuje następujące czynności:

Assigning task, parsing Adaptive Card, posting the Card to Teams
Przydzielanie zadania, przetwarzanie Adaptive Card, wysyłanie karty do Teams

(A) Przypisuję zadanie do menedżera, używając akcji „Create an approval (V2)”. Akcja tworzy zadanie dla osoby zatwierdzającej, ale nie wstrzymuje przepływu pracy do czasu jego zakończenia. Po prostu przypisuje zadanie i przechodzi dalej.

(B) Jednym z atrybutów zwracanych z akcji zadania jest kod JSON „Adaptive Card”. W pełni działający! Następnie parsuję go, aby móc pobrać z niego każdą właściwość, którą chcę:

Getting Adaptive Card code from Microsoft Flow approval and parsing it
Pobieranie kodu Adaptive Card z zadania Microsoft Flow i parsowanie go

Chciałem jednak zmienić jego wygląd i zastąpić go własnym:

Standard approval Adaptive Card vs. one I created
Standardowy interfejs Adaptive Card zatwierdzania vs. stworzony przeze mnie

Ważne! Adaptive Card generowana przez Flow ma właściwość „Actions”, która zawiera definicję przycisków „Approve” i „Reject”. Zawiera ona także wiele wartości wymaganych przez Flow Bot, aby poprawnie przeanalizować żądanie i zakończyć powiązane zadanie:

Data send back to Flow Bot once button on Adaptive Card is clicked
Dane wysyłane z powrotem do Flow Bot po kliknięciu przycisku na Adaptive Card

Mając to na uwadze, postanowiłem nie budować całkowicie własnej karty Adaptive Card, ale po prostu przygotować i użyć jej właściwości „Body”. Po przygotowaniu kodu wkleiłem go do akcji „Compose” (C) w Flow i zastąpiłem wartości właściwościami z przepływu, a na koniec zbudowałem nowy kod karty Adaptive Card łącząc informacje nagłówka oryginalnej karty ze spersonalizowaną treścią i akcjamm z oryginalnej karty (D):

Building new Adaptive Card code
Tworzenie kodu nowej karty Adaptive Card
  1. substring(body('Assign_approval_task_to_manager')?['adaptiveCard'], 0, indexOf(body('Assign_approval_task_to_manager')?['adaptiveCard'], '"body"'))
    Aby uzyskać nagłówek, a więc wszystkie informacje przed strukturą „body”.
  2. outputs('New_Body_part_of_card')
    Mój nowy kod „Body”.
  3. substring(body('Assign_approval_task_to_manager')?['adaptiveCard'], indexOf(body('Assign_approval_task_to_manager')?['adaptiveCard'], '"actions"'), sub(length(body('Assign_approval_task_to_manager')?['adaptiveCard']), indexOf(body('Assign_approval_task_to_manager')?['adaptiveCard'], '"actions"')))
    Aby uzyskać „Actions”, a więc wszystkie informacje po strukturze „Body”.

Tak przygotowany kod jest wysyłany za pomocą akcji „Post your own adaptive card as the Flow bot to a user (Preview)” do osoby zatwierdzającej (E).

Następne (5) przepływ zostaje wstrzymany w oczekiwaniu na zakończenie zadania. Po zatwierdzeniu zadania (za pomocą Adaptive Card w Teams lub przycisków w wiadomości e-mail, lub aplikacji mobilnej Flow) przepływ może przejść dalej. Następnie inicjuję zmienną, aby przechowywać komentarze zatwierdzenia (6). Ponieważ nie jest to pole wymagane w zadaniu, jest możliwe, że będzie puste. To z kolei sprawiało, że Flow się kończył błędem, kiedy następowała próba zapisania tej null-owej informacji w polu „Approval Comments” w CDS. Dlatego zdecydowałem się użyć opcji „Run after” w akcji „Set variable” i połączyć komentarz z pustym stringiem, co rozwiązało problem: (concat(outputs('Get_approval_comments'), '')):

Using "Run after" to join null string with empty one
Użycie „Run after” w celu złączenia null-owego stringa z pustym

Obsługa wyniku zatwierdzania

I tu zaczyna się finalny scope (7):

Najpierw aktualizuje (A) rekord wniosku w encji CDS przechowującej informacje o zatwierdzeniu: kto, kiedy, jaki jest wynik i komentarz. Następnie (B), w oparciu o wynik, wysyła kolejną kartę Adaptive Card do wnioskującego z informacją o akceptacji lub odrzuceniem wniosku:

Handling approval outcome
Obsługa wyniku zatwierdzania

Używając poniższych kart:

Approval and Rejection Adaptive Cards
Approval i Rejection Adaptive Cards

Następnie (C) dodaje wpis do kalendarza wnioskującego i managera na okres urlopu. Następnie generuje plik ICS, wykorzystując dane z przepływu i używając właściwego dla tego rodzaju pliku formatu. Wreszcie zapisuje plik w Aure Blob Storage:

Preparing and generating ICS file
Przygotowanie i generowanie pliku ICS

Ważne! Jeśli chcesz, aby Twój plik ICS został pobrany podczas wywoływania jego adresu URL, a nie wyświetlany w przeglądarce jako zwykły tekst, użyj „application/octet-stream” jako content type.

Wreszcie (E) aktualizuje limit dni pozostałych dla użytkownika i wysyła kartę Adaptive Card do kanału w Microsoft Teams, aby inni członkowie zespołu dowiedzieli się, kiedy ich kolega będzie nieobecny. Umożliwia także im pobranie wygenerowanego wcześniej pliku ICS, aby dodać ten fakt do ich kalendarzy:

Different Adaptive Cards sent to Microsoft Teams channel
Różne karty Adaptive Cards wysyłane do kanału w Microsoft Teams

I to wszystko! Mam nadzieje ze Ci się podobało.

Jeśli masz jakieś pytania lub chciałbyś, abym Ci pomógł w Twojej podróży z Adaptive Cards, zostaw komentarz lub skontaktuj się ze mną za pomocą formularza kontaktowego.