3 Features You Should Add To Your Power App
Tags: powerapps, powerplatform, lowcode
Published: 2022-12-15 09:59:29

One of the key strengths to Power Apps is the breadth of solutions apps can deliver (In this article Im focusing on Canvas apps), often you are only limited by your imagination. From mobile to desktop, consumption to creation, you can pretty much do anything. Even though you can create anything I still believe there are a few key functions/features every app should have. Unfortunately they are not out of the box in Power Apps, so you either need to code it in Power FX.

I wanted to share the 3 key ones that I always use and how I implemented them:

1. Translation
2. Inactivity/Session Timeouts
3. Dark Mode

---

## 1. Translation

It is a big surprise that there is no easy way to implement multiple languages in Power Apps (Even MS Forms has added it recently), fortunately there are multiple ways to implement it.

My solution focus on 2 main areas, performance and flexiability. With the trade off development is a little more complex. You can flip this and make it easier to implement, but in my expierence the trade off in app perfomance isnt worth it.

The solution structure is

- Excel Table with Translations
- Translation Collection
- Labels etc (Referencing row in collection through Index)

As you can see, a quick change would be to use lookups in the labels instead of Index, but thats where I found performance can be impacted, especially in complex apps.

**Excel Table with Translations**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3denszxsp94e5g2d84y.png)
_As you can tell Im not mulit-lingeral, so in development I often just have place holders for other languages. This allows me to test the functionality, but not request a translation until complete_

The structure is simple, an ID column that represents your Index value (this is purely to make development easier), then each langauge has its own column. And this is where the flexability of this approach shines, as to add languages you simply add a new column. To change a label or translation just update the required cell.

Once complete the excel file needs to be up uploaded into the app, we dont want to link it, as in theory it shouldnt get updated very often.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94k7ddmofaupp9ehpvzk.png)

**Translation Collection**

Now we have out translation we need a way of setting them, so I transfer the Excel table to a collection, but I use either the `Language` function, or I default to my required Language (as I often find the Langugage function inconsistent, due to how the laptop may have been setup by the IT dept)

```
ClearCollect(colTranslation,
    RenameColumns(
        ShowColumns(TranslationTable,"English")
    ,
        "English"
    ,  
        "local"
    )
)
```
_TranslationTable is the name of the Excel table_

I use the ShowColumns to select the language I want, and the RenameColumns so that all the lables etc reference same field. This way I only have to do one calcualtion on app starts, instead on every label.

To change the language a simple drop down can be configured to update the collection the same way, but selecting a different language field in the ShowColumns

```
Switch(Self.SelectedText.Value,
   Deutsche",ClearCollect(colTranslation,
      RenameColumns(ShowColumns(TranslationTable,"Deutsche"),"Deutsche","local")),
  "Polskie",ClearCollect(colTranslation,
      RenameColumns(ShowColumns(TranslationTable,"Polskie"),"Polskie","local")),
   ClearCollect(colTranslation,
      RenameColumns(ShowColumns(TranslationTable,"English"),"English","local"))
)
```

**Labels etc**

The last stage is how to use the transalation, and where the development complexity is added. You cant simply type the text you want, but you have to return the require row from the translation collection.

```
Index(trans,24).local
```

So in my example Excel table, the above would return 'Quantity Dispatched', in which ever language required (row/ID 24). So as a developer you will need to have the table availabe to lookup (another good reason to use an Excel file).

---

## 2. Inactivity/Session Timeouts

To say Im frustrated that this is not available out of the box is an understatment. Even more annoying is it is an environment config, but it only covers Model Driven Apps and not Canvas Apps (even more annoying this isnt clearly stated and hidden away in some documentation).

So if we need to add inactivity and session timeouts, we need to do it ourselves (and in my expierence this is a basic requirement asked for my Security). The solutions is not pretty, and requires the following:

- Configuration
- Timer to track if timed out
- Popup/logic to end sessions
- Resets on every interaction

**Configuration**

With timeouts it isnt actually one timeout, but normally 4.

- Inactivity Warning
- Inactivity Timeout
- Session Warning
- Session Timeout

_Session timeouts are the maximun amount of time someone can stay logged into an App, it doesnt stop people logging out and straight back in, but does enforce a check to see if the user still hase access_

I strongly recommend settings these values as environment variables, as that way you can set a lower limit in dev to help with testing (imagine having to wait 8 hours to test the session timeout).

I also genuinely put all the values in a single object to keep it tidy

```
Set(voMinutes,{
    inactivityWarning:LookUp('Environment Variable Values',
        'Environment Variable Definition'.'Schema Name'="new_STIPInactivityWarning").Value,
    inactivity:LookUp('Environment Variable Values',
         'Environment Variable Definition'.'Schema Name'="new_STIPInactivity").Value,
    sessionWarning:LookUp('Environment Variable Values',
         'Environment Variable Definition'.'Schema Name'="new_STIPSessionWarning").Value,
    session:LookUp('Environment Variable Values',
         'Environment Variable Definition'.'Schema Name'="new_STIPSession").Value
    }
);
```

voMinutes holds the minutes for each timeout, e.g

- Inactivity Warning = 10 minutes
- Inactivity Timeout = 15 minutes
- Session Warning = 465 minutes (7hrs 45 mins)
- Session Timeout = 480 minutes (8hrs)

We now need to set the actual time stamps that the timer will validate agains.

```
Set(voTimer,{
    inactivityWarning:DateAdd(Now(),voMinutes.inactivityWarning,Minutes),
    inactivity:DateAdd(Now(),voMinutes.inactivity,Minutes),
    sessionWarning:DateAdd(Now(),voMinutes.sessionWarning,Minutes),
    session:DateAdd(Now(),voMinutes.session,Minutes)
    }
);
```
These both should be ran on the App onStart action.

**Timer to track if timed out**

The timer is the main component of the timeouts, but unfortuantly it isnt as simple as a timer. When the Power App window loses focus the timer stops, so we cant have a simple timer. Instead we need to record a timestamp, and every second check that time stamp to see if we had hit a timeout threshould. We have set the timestamps and stored them in an object variable called `voTimer`, and we need to configured the timer with the following parameters

- AutoStart: true
- Duration: 1000 (1 second)
- Repeat: true
- Reset: true
- OnTimerEnd: (see below)

**Popup/logic to end sessions**

```
If(vbSessionStart,
    If(Now()>=voTimer.session Or Now()>=vsSessionTimeOut,
      //actions if session timer expired
    );
    If(Now()>=voTimer.inactivity,
       //actions if inactivity timer expired e.g
        Notify("Inactivity Timeout",NotificationType.Error,6000);
        Launch(vsExitURL,{source:"Inactivity"},LaunchTarget.Replace);
        Exit()
    );
    If(Now()>=voTimer.inactivityWarning,
      //actions to show inactivity warning popup
    );
    If(Now()>=voTimer.sessionWarning,
       //actions to show session warning popup e.g
        Set(vsExitMess,"Approaching "&voMinutes.session&" minutes limit, this session will end at:"&Text(voTimer.session,"hh:mm"));
        Set(visPopup,true);      
    )
)
```

We are first checking to see if voTimer has been loaded (`vbSessionStart`) as the timer is on AutoStart. Next we check if now is after the session timeout, then the inactivity timeout, then inactivity warning and finally session warning.

In the example for Inactivity timeout out, with flag a error notifcation, open a web page we want to show when signed out (`vsExitURL` variable) and then we exit the app. The warning is probably not needed as everything happens so fast, the browser will send us to the new page in the tab, and as a backup the app will close the app (add true with the Exit() if you wish to log them out of all Microsoft apps too).

The warning example sets a label variable to the required warning (that way re only have one popup for both warnings), and we set the popup to true with `visPopup`.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xrmw75w392jvggxiorue.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gcv1xemdssmfhwv9h8ku.png)

**Resets on every interaction**

So we have our timeouts set, how do we stop the inactivity warnings. Well heres the reason I realy wish there was an out of the box solution, we have to update the inactivity warning and timeout on every interaction (button click, dropdown change, even background click).

The function is pretty simple:

```
Set(voTimer,{
    inactivityWarning:DateAdd(Now(),voMinutes.inactivityWarning,Minutes),
    inactivity:DateAdd(Now(),voMinutes.inactivity,Minutes),
    sessionWarning:voTimer.sessionWarning,
    session:voTimer.session
    }
);
```

---

## 3. Dark Mode

Nearly all apps and websites now support dark mode, and although Power Apps doesn't have an out the box solution, its easy to create (fingers crossed Power Apps will in the furture support reading the OS and/or browsers current mode).

To create dark mode each component requires its colour parameters to be set to variables (RGBA can be stored directly in a variable). This has the added benefits of bening able to change the theme of your app quickly in future.

For simplicity I work on a 3 colour pallet, with each fill colour having corresponding text colour.

```
Set(voColour1,RGBA(60,60,58,1));
Set(voText1,bBlacklack);
Set(voColour2,RGBA(155,12,35,1));
Set(voText2,Black);
Set(voColour3,RGBA(219, 219, 219, 1));
Set(voText3,White);
Set(vbDarkMode,false);
```

A simple switch can then be used to flip darkmode on:

```
if(vbDarkMode,
  Set(voColour1,Black);
  Set(voText1,White);
  Set(voColour2,Black);
  Set(voText2,White);
,
  Set(voColour1,RGBA(60,60,58,1));
  Set(voText1,Black);
  Set(voColour2,RGBA(155,12,35,1));
  Set(voText2,Black);
);
Set(vbDarkMode,Not(vbDarkMode);
```

As you can see, not all colours may need changing.

The key to dark mode is to setup before development, as it is easy to copy and paste configured components, then configuring each as they are added.

---

There are lots of features that I often reuse in my apps, but these 3 are pretty much consistently now in every app. And all of the benefit from planning ahead and implementing at the beginning, rather then trying to add retrospectively.