Skip to content

Commit 7baf844

Browse files
Refactor code structure for improved readability and maintainability
1 parent 25057a0 commit 7baf844

2 files changed

Lines changed: 215 additions & 84 deletions

File tree

CLAUDE.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
66

77
This is a Power Fx snippets repository containing reusable code patterns, formulas, and components for Microsoft Power Platform development. The repository serves as a comprehensive collection of Power Apps development resources.
88

9+
Whenever we edit a file
10+
911
## Repository Structure
1012

1113
```
1214
PowerFxSnippets/
1315
├── Algorithms/ # Algorithm implementations and patterns
1416
├── App.Formulas/ # Named formulas and app-level formulas
1517
├── App.OnError/ # Error handling patterns
16-
├── App.OnMessage/ # Message handling patterns
18+
├── App.OnMessage/ # Message handling patterns
1719
├── App.OnStart/ # App initialization patterns
1820
├── App.StartScreen/ # Start screen configurations
1921
├── Components/ # Reusable Power Apps components
@@ -30,7 +32,7 @@ PowerFxSnippets/
3032
## Key File Types
3133

3234
- **`.md` files**: Documentation and code snippets in markdown format
33-
- **`.yaml` files**: Power Fx formula definitions and configurations
35+
- **`.yaml` files**: Power Fx formula definitions and configurations
3436
- **`.msapp` files**: Power Apps application packages
3537
- **`.csv` files**: Sample data sets
3638
- **`.svg` files**: Scalable vector graphics for UI elements
@@ -66,4 +68,4 @@ Document AI-assisted work sessions in `ai-chats/` using the format:
6668

6769
- Power Fx GitHub: https://github.com/microsoft/Power-Fx
6870
- PowerApps Tooling: https://github.com/microsoft/PowerApps-Tooling
69-
- Community Materials: https://tinyurl.com/DarrensStuffPower
71+
- Community Materials: https://tinyurl.com/DarrensStuffPower

Errors/Catch All Errors.md

Lines changed: 210 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
If you'd like to literally catch all errors in your canvas Power Apps, simply copy and paste the code shown below.
44

5-
Related content: https://youtu.be/8qcPq4peows 📺
5+
Related content: https://youtu.be/8qcPq4peows
66

77
## Prerequisites
88

@@ -16,6 +16,25 @@ Related content: https://youtu.be/8qcPq4peows 📺
1616

1717
---
1818

19+
## How It Works: Signature-Based Deduplication
20+
21+
This error handler uses **smart deduplication** to prevent email floods:
22+
23+
| What Happens | Old Behavior | New Behavior |
24+
|--------------|--------------|--------------|
25+
| Error A occurs 50× | 50 emails | 1 email |
26+
| Error B occurs 10× | 10 emails | 1 email (includes "Error A: 50×") |
27+
| **Total** | **60 emails** | **2 emails** |
28+
29+
### The Approach
30+
31+
1. **Unique Signatures** - Each error gets a signature: `Screen|Source|Message`
32+
2. **Collection Tracking** - `colErrorSignatures` stores unique errors with occurrence counts
33+
3. **Smart Emailing** - Only sends email on **first occurrence** of each unique error
34+
4. **Full Context** - Every email includes the **complete session error summary** with counts
35+
36+
---
37+
1938
## Step 1: Add Named Formulas to `App.Formulas`
2039

2140
Copy this code block to your **App.Formulas** property. Update the values as needed for your application.
@@ -53,115 +72,225 @@ Copy this code block to your **App.OnError** property. This code can remain unmo
5372

5473
```PowerFx
5574
// ============================================================================
56-
// ERROR HANDLER - Add to App.OnError
75+
// ERROR HANDLER WITH SIGNATURE-BASED DEDUPLICATION - Add to App.OnError
76+
// ============================================================================
77+
// Only sends email on FIRST occurrence of each unique error.
78+
// Subsequent occurrences just increment the counter - no spam!
5779
// ============================================================================
5880
With(
5981
{
82+
ScreenName: App.ActiveScreen.Name,
83+
MyUsersName: User().FullName,
84+
MyUsersEmail: User().Email,
85+
CurrentTime: Now(),
86+
LightGrayColorHexBG: "background-color:" & fxLightGrayColor & ";",
87+
CountBefore: CountRows(colErrorSignatures),
6088
SubjectLine: Concatenate(
6189
"Error(s) occurred in the ",
6290
fxApplicationName,
6391
" application for ",
6492
User().FullName
65-
),
66-
HowManyErrors: CountRows(AllErrors) + CountRows(colAppErrors),
67-
LightGrayColorHexBG: "background-color:" & fxLightGrayColor & ";",
68-
ScreenName: App.ActiveScreen.Name,
69-
MyUsersName: User().FullName,
70-
MyUsersEmail: User().Email
93+
)
7194
},
72-
// Collect all errors into the colAppErrors collection
73-
Collect(
74-
colAppErrors,
75-
ForAll(
76-
AllErrors As My,
95+
// Process each error - add new signatures or update existing counts
96+
ForAll(
97+
AllErrors As Err,
98+
With(
7799
{
78-
Kind: My.Kind,
79-
Message: Text(My.Message),
80-
Source: Text(My.Source),
81-
Observed: Text(My.Observed),
82-
HttpResponse: Text(My.Details.HttpResponse),
83-
HttpStatusCode: Text(My.Details.HttpStatusCode),
84-
TimeStamp: Text(Now(), "MM/dd/yyyy hh:mm:ss:ffff AM/PM"),
85-
Screen: ScreenName,
86-
UserEmail: MyUsersEmail,
87-
UsersName: MyUsersName
88-
}
100+
// Generate unique signature: Screen|Source|Message
101+
ErrSignature: ScreenName & "|" & Text(Err.Source) & "|" & Text(Err.Message)
102+
},
103+
If(
104+
IsBlank(LookUp(colErrorSignatures, Signature = ErrSignature)),
105+
// ═══════════════════════════════════════════════════════════
106+
// NEW UNIQUE ERROR - Add to tracking collection
107+
// ═══════════════════════════════════════════════════════════
108+
Collect(
109+
colErrorSignatures,
110+
{
111+
Signature: ErrSignature,
112+
Screen: ScreenName,
113+
Source: Text(Err.Source),
114+
Kind: Err.Kind,
115+
Message: Text(Err.Message),
116+
Observed: Text(Err.Observed),
117+
HttpResponse: Text(Err.Details.HttpResponse),
118+
HttpStatusCode: Text(Err.Details.HttpStatusCode),
119+
Occurrences: 1,
120+
FirstOccurrence: Text(CurrentTime, "MM/dd/yyyy hh:mm:ss AM/PM"),
121+
LastOccurrence: Text(CurrentTime, "MM/dd/yyyy hh:mm:ss AM/PM"),
122+
UserEmail: MyUsersEmail,
123+
UsersName: MyUsersName
124+
}
125+
),
126+
// ═══════════════════════════════════════════════════════════
127+
// EXISTING ERROR - Just increment counter, NO EMAIL
128+
// ═══════════════════════════════════════════════════════════
129+
Patch(
130+
colErrorSignatures,
131+
LookUp(colErrorSignatures, Signature = ErrSignature),
132+
{
133+
Occurrences: LookUp(colErrorSignatures, Signature = ErrSignature).Occurrences + 1,
134+
LastOccurrence: Text(CurrentTime, "MM/dd/yyyy hh:mm:ss AM/PM")
135+
}
136+
)
137+
)
89138
)
90139
);
91-
// Send email notification to developer(s)
92-
Office365Outlook.SendEmailV2(
93-
fxErrorHandlerEmail,
94-
SubjectLine,
95-
$"<html><body>
96-
<h3>Error Report for {MyUsersName} ({MyUsersEmail})</h3>
97-
<table style='width:100%;' border='1' cellpadding='10' cellspacing='0'>
98-
<tr style='{LightGrayColorHexBG} width:100%;'>
99-
<th>Time Stamp</th>
100-
<th>Screen Name</th>
101-
<th>Kind</th>
102-
<th>Source</th>
103-
<th>Message</th>
104-
<th>Observed</th>
105-
<th>Http Response</th>
106-
<th>Http Status Code</th>
107-
</tr>" &
108-
Concat(
109-
colAppErrors,
110-
$"<tr>
111-
<td>{TimeStamp}</td>
112-
<td>{Screen}</td>
113-
<td>{Kind}</td>
114-
<td>{Source}</td>
115-
<td>{Message}</td>
116-
<td>{Observed}</td>
117-
<td>{HttpResponse}</td>
118-
<td>{HttpStatusCode}</td>
119-
</tr>"
120-
) & $"
121-
<tr>
122-
<td colspan='8' style='{LightGrayColorHexBG}'>
123-
<div>
124-
From Application: <a href='{fxApplicationURL}'>{fxApplicationName}</a>
125-
</div>
126-
</td>
127-
</tr>
128-
</table>
129-
</body></html>"
140+
// ═══════════════════════════════════════════════════════════════════════
141+
// ONLY SEND EMAIL IF NEW UNIQUE ERROR(S) WERE ADDED
142+
// ═══════════════════════════════════════════════════════════════════════
143+
If(
144+
CountRows(colErrorSignatures) > CountBefore,
145+
Office365Outlook.SendEmailV2(
146+
fxErrorHandlerEmail,
147+
SubjectLine,
148+
$"<html><body>
149+
<h3>Error Report for {MyUsersName} ({MyUsersEmail})</h3>
150+
<p><strong>New unique error detected.</strong> Full session error summary below:</p>
151+
<table style='width:100%;' border='1' cellpadding='8' cellspacing='0'>
152+
<tr style='{LightGrayColorHexBG}'>
153+
<th style='text-align:center;'>Count</th>
154+
<th>Screen</th>
155+
<th>Kind</th>
156+
<th>Source</th>
157+
<th>Message</th>
158+
<th>First Seen</th>
159+
<th>Last Seen</th>
160+
</tr>" &
161+
Concat(
162+
colErrorSignatures,
163+
$"<tr>
164+
<td style='text-align:center;font-weight:bold;font-size:1.2em;'>{Occurrences}×</td>
165+
<td>{Screen}</td>
166+
<td>{Kind}</td>
167+
<td>{Source}</td>
168+
<td>{Message}</td>
169+
<td style='font-size:0.9em;'>{FirstOccurrence}</td>
170+
<td style='font-size:0.9em;'>{LastOccurrence}</td>
171+
</tr>"
172+
) & $"
173+
<tr>
174+
<td colspan='7' style='{LightGrayColorHexBG}'>
175+
<div>
176+
<strong>Total unique errors:</strong> {CountRows(colErrorSignatures)} |
177+
<strong>Total occurrences:</strong> {Sum(colErrorSignatures, Occurrences)}
178+
</div>
179+
<div style='margin-top:8px;'>
180+
From Application: <a href='{fxApplicationURL}'>{fxApplicationName}</a>
181+
</div>
182+
</td>
183+
</tr>
184+
</table>
185+
</body></html>"
186+
)
130187
);
131188
);
132189
```
133190

134191
---
135192

193+
## Collection Schema: `colErrorSignatures`
194+
195+
This collection is automatically created and managed by the error handler:
196+
197+
| Field Name | Type | Description |
198+
|-----------------|--------|-------------|
199+
| Signature | Text | Unique key: `Screen\|Source\|Message` |
200+
| Screen | Text | Screen where error occurred |
201+
| Source | Text | Control/function that caused error |
202+
| Kind | Text | Error type (Sync, Network, etc.) |
203+
| Message | Text | Error message text |
204+
| Observed | Text | Where error was observed |
205+
| HttpResponse | Text | HTTP response (if applicable) |
206+
| HttpStatusCode | Text | HTTP status code (if applicable) |
207+
| Occurrences | Number | How many times this error occurred |
208+
| FirstOccurrence | Text | Timestamp of first occurrence |
209+
| LastOccurrence | Text | Timestamp of most recent occurrence |
210+
| UserEmail | Text | User's email address |
211+
| UsersName | Text | User's display name |
212+
213+
---
214+
215+
## Optional: View Error Collection in App
216+
217+
Add a gallery to a debug/admin screen to see all tracked errors:
218+
219+
```PowerFx
220+
// Gallery Items property
221+
colErrorSignatures
222+
223+
// Useful label formulas for the gallery template
224+
ThisItem.Occurrences & "× - " & ThisItem.Message
225+
"First: " & ThisItem.FirstOccurrence
226+
"Last: " & ThisItem.LastOccurrence
227+
```
228+
229+
---
230+
231+
## Optional: Clear Errors on App Start
232+
233+
Add to `App.OnStart` if you want a fresh collection each session:
234+
235+
```PowerFx
236+
Clear(colErrorSignatures);
237+
```
238+
239+
---
240+
136241
## Optional: Persist Errors to a Data Source
137242

138243
If you'd like to store errors in a database or SharePoint list for historical tracking:
139244

140245
### Step 1: Create a Data Source
141246

142-
Create a table/list named `PowerAppsErrors` with these fields (all single-line text):
247+
Create a table/list named `PowerAppsErrors` with these fields:
143248

144-
| Field Name | Type |
145-
|----------------|--------|
146-
| Kind | Text |
147-
| Message | Text |
148-
| Source | Text |
149-
| Observed | Text |
150-
| HttpResponse | Text |
151-
| HttpStatusCode | Text |
152-
| TimeStamp | Text |
153-
| Screen | Text |
154-
| UserEmail | Text |
155-
| UsersName | Text |
249+
| Field Name | Type |
250+
|-----------------|--------|
251+
| Signature | Text |
252+
| Screen | Text |
253+
| Source | Text |
254+
| Kind | Text |
255+
| Message | Text |
256+
| Observed | Text |
257+
| HttpResponse | Text |
258+
| HttpStatusCode | Text |
259+
| Occurrences | Number |
260+
| FirstOccurrence | Text |
261+
| LastOccurrence | Text |
262+
| UserEmail | Text |
263+
| UsersName | Text |
156264

157-
### Step 2: Add to End of App.OnError
265+
### Step 2: Persist on App Close
158266

159-
Add these lines at the end of the `App.OnError` code (after the `Office365Outlook.SendEmailV2` call):
267+
Add to a "Save & Exit" button or similar:
160268

161269
```PowerFx
162-
// Persist errors to data source and clear collection
163-
Patch(PowerAppsErrors, colAppErrors);
164-
Clear(colAppErrors);
270+
// Persist all unique errors with their occurrence counts
271+
ForAll(
272+
colErrorSignatures,
273+
Patch(
274+
PowerAppsErrors,
275+
Defaults(PowerAppsErrors),
276+
{
277+
Signature: Signature,
278+
Screen: Screen,
279+
Source: Source,
280+
Kind: Kind,
281+
Message: Message,
282+
Observed: Observed,
283+
HttpResponse: HttpResponse,
284+
HttpStatusCode: HttpStatusCode,
285+
Occurrences: Occurrences,
286+
FirstOccurrence: FirstOccurrence,
287+
LastOccurrence: LastOccurrence,
288+
UserEmail: UserEmail,
289+
UsersName: UsersName
290+
}
291+
)
292+
);
293+
Clear(colErrorSignatures);
165294
```
166295

167296
---

0 commit comments

Comments
 (0)