Näin yksi päivä Twitterissä João Mendes:in tekemän SPFx-sovelluksen, joka visualisoi hienosti työntekijöiden tulevia syntymäpäiviä.
Ensimmäinen ajatukseni oli, miten saman voisi tehdä Power Appsilla. Vieläpä ilman premium-ominaisuuksia, jolloin sovelluksen voisi ottaa käyttöön kaikkialla organisaatiossa.
Tuumasta toimeen.
Vastoinkäymisiä syntymäpäivien hakemisessa
Office -ympäristössä henkilöt voivat lisätä, tai olla lisäämättä, syntymäpäivänsä Delve-profiiliinsa.

Sovellus tarvitsee lähtötiedoksi käyttäjien syntymäpäivät. Siltä osin kuin ne löytyvät. Helppo homma! Haetaan vain kaikkien käyttäjien tiedot Office365 Users -yhdistimellä.
Mutta sehän ei palauta henkilöiden syntymäpäiviä!

Uskottava se on. Hetken kun testaa Graph API:a, niin käy selväksi ettei syntymäpäivätietoa saa mukaan käyttäjälistaan.

Yksittäisen käyttäjän tiedoissa syntymäpäivä on onneksi mukana.

Tämä tulee vaikuttamaan ikävästi Power Appsimme suorituskykyyn. Jatketaan silti ja murehditaan mahdollista hitautta myöhemmin.
Käyttäjälistan suodattaminen
Tehdään aluksi hieman valmisteluja näytön OnVisible -tapahtumassa.
Ensimmäisenä haemme kaikki ympäristön käyttäjät ja tallennamme ne kokoelmaan (colUsers).
ClearCollect(
colUsers,
Office365Users.SearchUserV2({isSearchTermRequired: false}).value
);

Kokoelma sisältää mm. vieraskäyttäjät ja erilaisia admin-tilejä. Suodatetaan ne pois. Otetaan mukaan ainoastaan käyttäjät joiden
- Etunimi on määritelty
- Sähköpostiosoite päättyy ”forwardforever.com”
- UserPrincipalName ei ala sanalla ”Admin”
Eli näin.
ClearCollect(
colFilteredUsers,
Filter(
colUsers,
GivenName <> Blank() And
EndsWith(Mail,
"forwardforever.com"
) And
!StartsWith(UserPrincipalName, "Admin")
)
);
Käyttäjien syntymäpäivien hakeminen
Nyt meillä on kokoelma, jossa on oikeat käyttäjät. Seuraavaksi luomme toisen kokoelman (colUsersWithBirthdays), johon haetaan käyttäjien tiedot yksi kerrallaan.
Mikäli käyttäjän syntymäpäivää ei tiedetä, on sen arvona 1. Tammikuuta vuonna 1. Otetaan siis mukaan ainoastaan käyttäjät, joiden syntymäpäivä ei ole vuonna 1.
Clear(colUsersWithBirthdays);
ForAll(
colFilteredUsers,
With(
{varUser: Office365Users.UserProfileV2(ThisRecord.Id)},
If(
Year(varUser.birthday) > 1,
Collect(
colUsersWithBirthdays,
{
jobTitle: varUser.jobTitle,
id: varUser.id,
displayName: varUser.displayName,
birthday: varUser.birthday
}
)
)
)
);
Seuraavat syntymäpäivät?
Lisätään näytölle galleria, joka esittää kokoelman (colUsersWithBirthdays) sisällön.

Seuraava ongelma on rivien järjestäminen. Haluamme listan ensimmäiseksi seuraavan syntymäpäivän.
Manipuloidaan hieman henkilöiden syntymäpäiviä.
- Muutetaan syntymäpäivät kuluvalle vuodelle (varBirthday)
- Mikäli syntymäpäivä on jo mennyt, siirretään se seuraavalle vuodelle (DateAdd(varBirthday,1,Years))
Collect(colUsersWithBirthdays,
{
jobTitle: varUser.jobTitle,
id: varUser.id,
displayName: varUser.displayName,
birthday: With({varBirthday:
Date(Year(Today()),
Month(varUser.birthday),
Day(varUser.birthday))
},
If(varBirthday < Today(),
DateAdd(varBirthday,1,Years),
varBirthday
)
)
}
)
Nyt voimme järjestää rivit syntymäpäivän mukaan ja ne ovat juuri siinä järjestyksessä kuin haluamme.

Syntymäpäivien esittäminen
Ennen sovelluksen viimeistelyä täytyy ratkaista vielä yksi ongelma. Mitä jos usella henkilöllä on syntymäpäivä samana päivänä?

Haluamme tällöin esittää syntymäpäivät yhtenä rivinä, jossa on kaikki ko päivänä syntymäpäiväänsä viettävät työntekijät. Tähän tapaan.

Miten tämä toteutetaan?
Vaihtoehto 1 – Ryhmittely (GroupBy)
Luodaan uusi kokoelma, jossa rivit on ryhmitelty syntymäpäivän (birthday) perusteella.
ClearCollect(colGroupedBirthdays, GroupBy(colUsersWithBirthdays,"birthday", "employees"));
Tässä kokoelmassa kutakin syntymäpäivää kohden on taulukko (table), joka sisältää ko päivän syntymäpäiväsankarien tiedot.

Pääsemme haluttuun lopputulokseen käyttämällä sisäkkäisiä gallerioita. Ulompi esittää syntymäpäivät (galBirthdays) ja sisempi (galEmployees) kyseisen päivän päivänsankarit.

Mutta sisäkkäiset galleriat ovat aina vähän säätöä. Yritetään jotain muuta.
Vaihtoehto 2 – HtmlText-kontrollin hyödyntäminen
Huomattavasti tehokkaampi tapa on käyttää HtmlText-kontrollia. Lisätään sellainen galleriaan ja näytetään siinä kyseisen päivän päivänsankarit html-formaatissa. Kukin päivänsankari omassa kappaleessaan (<p>).
Concat(ThisItem.employees, "<p>" & displayName & "</p>")
Lopuksi vaihdetaan kontrollin korkeus määrittymään automaattisesti sisällön mukaan (Auto height = true).

Valitettavasti emme voi esittää HtmlText-kontrollin avulla käyttäjien profilikuvia. Hyvä idea on hylättävä.
Vaihtoehto 3 – Päivämäärä-otsikoiden lisääminen kokoelmaan
Päädymme lopulta siihen tavallisen ratkaisuun. Lisätään alkuperäiseen kokoelmaan tarvittavat otsikkorivit. Eli tällä kertaa päivämäärät.
Otsikkorivit tulee kyetä erottamaan varsinaisista synttäririveistä. Lisätään kokoelmaan uusi sarake ”sortOrder”. Alkuperäisillä riveillä sillä on arvona 2.

Otsikkorivien lisääminen on suoraviivaista.
- Poimitaan alkuperäisestä kokoelmasta syntymäpäivät siten, että kukin syntymäpäivä esiintyy vain kerran (Distinct)
- Lisätään tulosjoukkoon uusi sarake (AddColumns, sortOrder) ja sille arvo 1
- Vaihdetaan (RenameColumns) sarakkeen ”Results” nimeksi ”birthday”
ClearCollect(colHeaders,
RenameColumns(
AddColumns(
Distinct(
colUsersWithBirthdays,
birthday
),
"sortOrder",
1
),
"Result",
"birthday"
)
);
Lopputulos näyttää seuraavalta.

Lisätään muodostettu kokoelma osaksi alkuperäisestä kokoelmaa.
Collect(colUsersWithBirthdays,colHeaders);
Nyt meillä on kaikki tarpeellinen kasassa. Lisätään näytölle joustavan korkuinen (flexible height) galleria ja järjestetäänsen rivit syntymäpäivän ja järjestysnumeron perusteella.
Näin listassa on aina ensin otsikkorivi syntymäpäivälle (Header) ja sen jälkeen varsinaiset sankarit (Employees).

Näyttää vielä hieman karulta. Siistitään galleriaa hieman.
Viimeistely
Näytetään päivämäärä-kenttä ainoastaan, mikäli kyseinen rivi on otsikkorivi (sortOrder=1). Vastaavasti henkilön nimi ja titteli näytetään vain, mikäli rivi ei ole otsikkorivi (sortOrder=2).
Vaihdetaan samalla hieman tekstikokoja ja värejä.

Muotoillaan päivämäärä-kenttä ja lisätään henkilön kuva.
- Päivämäärä: Text(ThisItem.birthday,”d mmmm”)
- Kuva: IfError(Office365Users.UserPhotoV2(ThisItem.id),””)

Mikäli juuri tänään on jonkun syntymäpäivä, näytetään onnitteluteksti kakkuineen.
Onnitteluteksti näytetään vain otsikkorivillä. Ei enää saman päivän synttärisankaririveillä.
Visible = IsToday(ThisItem.birthday) And ThisItem.sortOrder =1

Viimeisenä silauksena lisätään gallerian vasempaan reunaan jana (ympyrä + viiva), jonka väri on punainen mikäli kyseinen päivä on tänään.

Kahdessa viimeisessä vaiheessa saa jo hieman säätää kontrollien korkeuksia ja sijainteja sen mukaan onko kyseessä kuluva päivä vai ei. Huomaat kyllä jos oikeasti kokeilet tehdä tätä.
Lopputulos on varsin siisti.

Mitä tehdä hitaudelle?
Ai niin se hitaus… Sovelluksen käynnistyminen kestää usean sekunnin. Syy on selvä. Joudumme hakemaan käyttäjien syntymäpäivät yksi kerrallaan. Ei järin kestävä ratkaisu.
Ensi viikon jutussa selvitetään, mitä sille voisi tehdä.