Saman koodin kopioiminen useaan paikkaan sovellusta voi tuntua harmittomalta. Ylläpidettävyyden näkökulmasta se on kuitenkin myrkkyä. Huomaat tekeväsi samoja muutoksia ja/tai korjauksia useaan paikkaan. Ja toivot että muistit kaikki paikat, joihin olet koodin kopioinut.

Valitettasti uudelleenkäytettävien koodinpätkien luominen Power Appsissa ei ole kovin intuitiivista/helppoa.

Yritetään kuitenkin.

Käydään läpi kaksi tapaa kierrättää samaa koodia Power Appsin sisällä. Painikkeet ja komponentit.

Esimerkki – Viestin lähettäminen Teamsiin

Tehdään aluksi yksinkertainen Power Apps, jolla kommentoidaan toimenpiteitä.

Kommentista syntyy viestin Teamsin kanavalle. Toimenpiteillä on kanavalla omat säikeensä. Jos sellaista ei vielä ole, se luodaan.

Lähetä-painikkeen OnSelect-tapahtuma voisi olla seuraavankaltainen.

  • Mikäli valittua toimenpidettä vastaavaa säiettä ei löydy, niin
    • luodaan sellainen (PostMessageToChannelV3)
    • tallennetaan luodun säikeen tunniste (varCretedThread) toimenpiteelle (Actions)
  • Mikäli toimenpiteelle on jo tallennettuna säikeen tunniste, lähetetään viesti kyseiseen säikeeseen (PostReplyToMessage)
If(
    IsBlank(galActions.Selected.ThreadId),
    Set(
        varCreatedThread,
        MicrosoftTeams.PostMessageToChannelV3(
            varSelectedGroupID,
            varSelectedChannelId,
            {
                content: inpMessage.Text,
                contentType: "html"
            },
            {subject: "Thread for " & galActions.Selected.Name}
        ).id
    );
    Patch(
        Actions,
        galActions.Selected,
        {ThreadId: varCreatedThread}
    ),
    MicrosoftTeams.PostReplyToMessage(
        GUID(varSelectedGroupID),
        varSelectedChannelId,
        galActions.Selected.ThreadId,
        {
            content: inpMessage.Text,
            contentType: "html"
        }
    )
)

Haluame lähettää vastaavalla tavalla viestejä muualtakin sovelluksestamme. Esimerkiksi kun käyttäjä muokkaa toimenpidettä. Tai avaa toimenpiteen muokattavaksi. Helpointa on vain kopioda sama koodi kaikkialle missä sitä tarvitaan, mutta lopputulos on läjäpäin samaa koodia eri paikoissa.

Se ylläpitäjän painajainen.

Piilotettu painike

Tiesitkö että Power Appsin painiketta voi käyttää funktion tapaan?

Luodaan uusi painike (btnSendTeamsNotification) ja piilotetaan se näkyvistä (visible = false).

Painikkeen OnSelect-tapahtumassa lähetetään viesti ja tarvittaessa luodaan uusi säie. Siis sama koodi kuin alkuperäisessä painikkeessa. Mutta kaikki viestin lähettämiseen liittyvät parametrit on vaihdettu käyttämään muuttujia (varTopic, varMessage, varThreadID jne).

Alkuperäisen kommenentin lähetyspainikkeen OnSelect-tapahtuma muuttuu samalla kokonaan. Siinä

  • päivitetään viestin lähetykseen liittyvät muuttujat
  • painetaan näkymätöntä painiketta (Select(btnSendTeamsNotification))

Eristimme yksinkertaisella tavalla koodin yhteen paikkaan (piilotettuun painikkeeseen). Nyt voimme käyttää sitä useasta paikasta. Esimerkiksi lähettää viestin aina, kun käyttäjä valitsee galleriasta toimenpiteen.

Mutta… Painikkeen tulee sijaita samalla näytöllä kontrollin kanssa, josta sitä ohjelmallisesti painetaan.

Rajaa käyttökohteita aika paljon.

Koodin kierrättäminen komponentin avulla

Otetaan askel eteenpäin ja siirretään yleiskäyttöinen koodinpätkämme komponenttiin.

Luodaan uusi komponentti (cmpTeamsNotification), jolla on seurravat input-tyyppiset ominaisuudet

  • Viestin sisältö (Message)
  • Viestin otsikko (Subject)
  • Tiimin tunniste (TeamID)
  • Kanavan tunniste (ChannelID)
  • Säikeen tunniste (ThreadID)

Luodaan komponentille myös boolean-tyyppinen ominaisuus (Reset). Tämän ominaisuuden arvon muuttaminen aiheuttaa komponentin sisäisen OnReset-tapahtuman (Raise OnReset when value changes).

Käytännössä välitämme komponentille perinteisillä input-ominaisuuksilla koodin tarvitsemat parametrit. Reset-ominaisuuden avulla suoritamme koodin.

Sijoitetaan Teams-viestin lähetyskoodi komponentin OnReset-tapahtumaan.

Oteaan lopuksi komponentti käyttöön. Lisätään se sovelluksen näytölle ja käytetään sen ominaisuuksien arvoina aiemmin luomiamme muuttujia (varTopic, varMessage, varThreadID jne).

Komponentin Reset-ominaisuus saa arvokseen uuden muuttujan varResetComponent.

Lopuksi lisätään näytölle painike, jota painettaessa (OnSelect) muuttujien arvot asetetaan kohdilleen. Viimeisenä vaiheena suoritetaan komponentin sisältämä koodi (vaihtamalla varResetComponent-muuttujan arvoa).

Eli näin.

UpdateContext(
    {
        varGroupID: Gallery1.Selected.id,
        varChannelID: Gallery1_1.Selected.id,
        varThreadID: galActions.Selected.ThreadId,
        varMessage: inpMessage.Text,
        varTopic: galActions.Selected.Name,
        varResetComponent: !varResetComponent
    }
);

Nyt voimme käyttää samaa koodinpätkää kaikilta sovelluksemme näytöiltä!

Komponentti ei ole vielä kovin monikäyttöinen. Sen sisällä päivitetään Actions-taulun riville sitä vastaava säikeen tunniste (ThreadID).

Entä jos haluaisimme käyttää samaa koodia lähettämään viestejä toimenpiteen lisäksi myös esim päätöksistä, jotka ovat tallennettu omaan tauluunsa?

Aidosti yleiskäyttöisen komponentin toteuttaminen

Muutetaan komponenttiamme lopuksi siten, että se tekee ainoastaan sille määritellyn tehtävän. Lähettää viestin Teamsiin ja luo tarvittaessa sille uuden säikeen. Luodun säikeen tunnisteen tallentaminen oikeaan paikkaan jätetään kutsujan tehtäväksi.

Näin komponentin ei tarvitse tietää, mihin tauluun säikeen tunniste milloinkin pitäisi tallentaa. Tai pitäisikö sitä edes tallentaa. Komponenttia voi näin käyttää myös muissa sovelluksissa.

Toteutusta varten tarvitsemme käyttöömme ominaisuudet, jotka aiheuttavat omia tapahtumia (behaviour properties).

Luodaan uusi ominaisuus (NewThreadIsCreated). Tyypiltään se on Behaviour.

Ja sille parametri (ThreadID).

Muutetaan komponentin OnReset-koodia siten että uuden säikeen luonnin yhteydessä luodaan NewThreadIsCreated-tapahtuma (event). Se saa paramterikseen juuri luodun säikeen tunnisteen (varCreatedThread).

cmpTeamsNotification.NewThreadIsCreated(varCreatedThread)

Näytöllä komponentin koodi suoritetaan entiseen tapaan. Resetoimalla komponentti. Mutta mikäli komponentti luo uuden säikeen, saamme sen kiinni NewThreadIsCreated-tapahtumassa. Lisätään sinne koodi joka tallentaa luodun säikeen tunnisteen toimenpiteelle.

Patch(
    Actions,
    LookUp(
        Actions,
        Action = galActions.Selected.Action
    ),
    {ThreadId: ThreadID}
);

Yhteenveto

Tässä vaiheessa lienee selvää, miksi kansalaiskehittäjät kopioivat samaa koodia ympäri sovellusta. Power Appsissa ei ole funktioita ja uudelleenkäytettävien koodipätkien rakentaminen on hankalaa kikkailua.

Oleellista on myös ymmärtää että molemmissa ratkaisuissamme (painike ja komponentti) koodi ajetaan rinnakkain kutsuvan koodin kanssa.

Eli kuvan koodissa painikkeen painamisen (Select) jälkeen heti perään tulee ilmoitus (Notify). Ei vasta sitten, kun viesti on oikeasti lähetetty.