What you're building
3rd party inventory SharePoint list — with an automatic email to the IAM team. Part 1 builds the form itself; Part 2 adds validation and guidance; Part 3 wires up submission, notification and publishing.colSystems — not in the on-screen controls. Each input immediately writes its value back into the collection the moment it changes. That one habit makes the whole app safe: rows can scroll out of sight, rows can be deleted from the middle, and nothing is ever lost or shuffled, because the collection — not the controls — is the single source of truth. Step A10 will make you prove this to yourself.<YOUR-SITE-URL> (your SharePoint site) or <IAM-DL-EMAIL> (the IAM distribution list address), substitute your own values. Everything else is paste-as-is.galSystems is a value you enter — tap the chip to copy it (the ⧉ mark is the reminder), then paste it where the step says. A key cap like Ctrl+A is pressed on the keyboard. Dark boxes are complete formulas with their own Copy button. Paste, never retype.Text label · Text input · Drop down · Button · Rectangle · Blank vertical gallery. After inserting, rename the control: double-click its name in the Tree view → paste the new name → Enter.First, the list
A1Check the 3rd party inventory list
The list already exists — this step makes sure it looks exactly the way the formulas in Part 3 expect. Open <YOUR-SITE-URL> in the browser → gear icon (top right) → Site contents → click 3rd party inventory → gear icon again → List settings. The Columns section lists every column with its Type right beside the name — that's where you confirm everything below. Compare it against this table:
| # | Display name | Expected type | Form fills it? |
|---|---|---|---|
| 1 | Application Name | Text (likely the renamed Title) | Yes |
| 2 | ⚠ Vendor/ Provider Name — space after the / | Text | Yes |
| 3 | ⚠ Business owner — lowercase o | Text | Yes |
| 4 | Application Purpose | Multiline text | Yes |
| 5 | IT Custodian | Text | Yes |
| 6 | Admin Accounts Used | Text | Yes |
| 7 | ⚠ Permissions / Access levels — lowercase l | Multiline text | Yes |
| 8 | Support / Vendor Contact Information | Text | Yes |
| 9 | IAM Role | Text — assumed | Yes |
| 10 | Access Link | Text | Yes |
| 11 | ⚠ Division␠ — trailing space in the name | Text — assumed | Yes |
| 12 | Status | Text — assumed | Yes |
| 13 | Submission Date | Date and Time — assumed | Yes (auto) |
| 14 | IAM Notes | Text | No |
| 15 | Submission Cycle | Text | No |
| 16 | Handover Status | Text — assumed | Yes |
| 17 | Number of Accounts | Text — assumed | Yes |
| 18 | Report Export | Yes/No | No |
| 19 | Onboarded to IAM Platform | Yes/No | No |
| 20 | Access Review Status | Text | No |
| 21 | Review Frequency | Text | No |
Six assumed types — glance and confirm
Six columns marked "assumed" above had ambiguous types; this guide commits to the common-sense ones below (the live list data backs them). While you're in List settings, glance at each — and if one differs, nothing breaks: step C5 (Part 3) has a one-line fix per column, clearly marked.
IAM Role— Single line of textDivision␠(the one with the trailing space) — Single line of textStatus— Single line of textHandover Status— Single line of textNumber of Accounts— Single line of textSubmission Date— Date and Time
Only note a column down if its type is different from the list above — that note is all C5 needs.
Two checks and one addition while you're here:
- Title check. If
Application Nameis the renamed built-in Title column (it usually is), that's fine. What matters: there must be no separate Title column still marked "Require that this column contains information" — that would make every submission fail in Part 3. To check: List settings → Columns → click Title → "Require that this column contains information" must be No. - Add the audit columns (skip if they already exist). List settings → Create column → name
Responder Name→ type Single line of text → OK (or, from the list view itself: + Add column → Single line of text). Repeat forResponder Email.
Vendor/ Provider Name (space after the slash), Business owner (lowercase o), Permissions / Access levels (lowercase l), and Division (trailing space). Do not rename them — live data and the formulas in this guide both use them as-is. In Power Apps you'll always accept IntelliSense autocomplete rather than hand-typing these. And when this guide writes Division␠, the ␠ just marks the invisible trailing space — on screen the column looks like plain "Division".Responder Name and Responder Email exist as Single line of text columns.The app shell
A2Create the app and set three settings
- Go to
make.powerapps.com(check the correct environment, top right) → Create → Start with a blank canvas → Tablet size. If a dialog asks for the app's name right away, pasteThird-Party Application Declarationthere. Studio opens with an empty Screen1. - Settings (gear icon, or File → Settings) → Display: confirm size is
1366×768. - Settings has a search box — type
modernto find Modern controls and themes → turn it OFF. This guide names classic properties (HintText,Default,BorderColor) — modern controls would rename half of them. - Same search box → type
errorto find Formula-level error management → turn it ON. Part 3's submit formula usesIfError, which needs this switch. - Tree view → double-click Screen1 → rename to
scrMain.
Third-Party Application Declaration. Autosave takes over from here.scrMain · modern controls off · formula-level error management on.A3Connect the SharePoint list
- Left rail → Data (cylinder icon) → Add data → search
SharePoint→ pick the SharePoint connector (sign in if asked). - In the site picker, paste
<YOUR-SITE-URL>(or pick the site from Recent) → Connect. - Tick
3rd party inventoryin the list of lists → Connect.
3rd party inventory as a connected data source.A4App.OnStart — collections, flags, and the first blank row
Tree view → click App → property dropdown (top-left, next to the fx bar) → OnStart → Ctrl+A → paste:
App · OnStart
Set(gblColorBrand, ColorValue("#C8102E"));
Set(gblColorInk, ColorValue("#1B2436"));
Set(gblColorPaper, ColorValue("#F4F5F8"));
ClearCollect(colIAMRoles, ["Manage", "Govern", "Not Involved"]);
ClearCollect(colStatusValues, ["Active", "Decommissioned"]);
ClearCollect(colHandoverValues, ["Handover Not Required", "Handed Over", "Pending Handover"]);
ClearCollect(colDivisions, ["Operations & Administration", "Information Technology", "Financial Planning & Control", "Human Resources", "Strategy & Transformation", "Marketing & Communications", "Corporate & Business Development", "Remedial", "In - Business Risk", "Treasury & Investment", "Private Banking & Wealth Management", "International Banking", "Wholesale Banking", "Retail Banking", "Corporate Secretariat", "Information Security", "Risk Management", "Credit & Overseas Risk", "Compliance & AML", "Internal Audit", "Legal"]);
Set(gblShowErrors, false);
Set(gblShowConfirm, false);
Set(gblShowSuccess, false);
Set(gblSubmitting, false);
Set(gblNextSeq, 2);
ClearCollect(colSystems, {RowID: GUID(), SeqNo: 1, AppName: "", Vendor: "", BizOwner: "", Purpose: "", Custodian: "", AdminAccts: "", Permissions: "", SupportContact: "", IAMRole: "", AccessLink: "", Division: "", Status: "", Handover: "", NumAccts: ""})Then run it once: Tree view → hover App → ⋯ → Run OnStart.
colSystems — the form's single source of truth — seeded with one blank row (SeqNo 1, every field empty).colSystems holds exactly 1 row; colDivisions holds 21 rows.A5The header band
Four controls on scrMain. For each: + Insert → search box → the control's search term → click it → rename in the Tree view (double-click the name → paste → Enter) → set X/Y/Width/Height in the Properties pane on the right. Two standing motions, used here and in every later step: every quoted Text value goes in via property dropdown (top-left, next to the fx bar) → Text → Ctrl+A → paste (quotes included); every colour goes in via property dropdown → Color (or Fill) → Ctrl+A → paste.
- + Insert → search
Rectangle→ renamerecHeader→ X0· Y0· Width1366· Height80. Property dropdown → Fill → Ctrl+A → paste:gblColorBrand - + Insert → search
Text label→ renamelblAppTitle→ X24· Y10· Width800· Height36→ Text:"Third-Party Application Declaration"→ right pane: Font size22, Bold → Color:Color.White. - + Insert → search
Text label→ renamelblAppSubtitle→ X24· Y46· Width800· Height26→ Text:"Declare the third-party systems your division uses — all fields are required"→ right pane: Font size14→ Color:Color.White. - + Insert → search
Text label→ renamelblUserBadge→ X1020· Y24· Width322· Height32→ right pane: Font size14, text alignment Right → Color:Color.White. Then property dropdown → Text → Ctrl+A → paste:
lblUserBadge · Text
User().FullNamegblColorBrand is the brand red set in OnStart. If branding ever changes, one line in OnStart re-skins the app.The multi-row form
A6The gallery — one card per system
- + Insert → search
Blank vertical gallery→ click it. Rename itgalSystems. - The Items panel may pop up asking for a data source — choose
colSystems(or set the property dropdown → Items → Ctrl+A → pastecolSystems). - Properties pane: X
0· Y96· Width1366· Height580. - Property dropdown → TemplateSize → Ctrl+A → type:
600 - Now click the pencil icon in the gallery's top-left corner — this puts you inside the template, so everything you insert next lands in the row, not on the screen. + Insert → search
Rectangle→ renamerecRowCard→ X8· Y8· Width1318· Height584. Then three property pastes: Fill → Ctrl+A →RGBA(255, 255, 255, 1)· BorderColor → Ctrl+A →RGBA(201, 204, 213, 1)· BorderThickness → Ctrl+A →1. - Still inside the template: + Insert → search
Text label→ renamelblRowNum→ X16· Y14· Width200· Height28→ Bold. Property dropdown → Text → Ctrl+A → paste:
lblRowNum · Text
"System " & ThisItem.SeqNo- Still inside the template: + Insert → search
Button→ renamebtnDeleteRow→ X1180· Y14· Width130· Height32→ Text:"Delete Row"(property dropdown → Text → Ctrl+A → paste). Property dropdown → OnSelect → Ctrl+A → paste:
btnDeleteRow · OnSelect
Remove(colSystems, ThisItem)TemplateSize stays a fixed 600. Do not switch to a flexible-height gallery — inputs inside flexible-height galleries misbehave, and this guide's geometry assumes fixed rows.App → ⋯ → Run OnStart brings it back.)A7Left column — seven fields
Seven label + input pairs, all inside the gallery template (pencil icon first — check the breadcrumb above the canvas says you're in galSystems). The drill for every field: + Insert → search Text label, rename, position, set Text (property dropdown → Text → Ctrl+A → paste, quotes included) · + Insert → search Text input, rename, position · property dropdown → Default → Ctrl+A → paste · property dropdown → OnChange → Ctrl+A → paste. All labels and inputs: X 16 · Width 630. Labels Height 20, inputs Height 40.
1 · Application Name. Label lblAppName at Y 48, Text "Application Name". Input txtAppName at Y 72:
txtAppName · Default
ThisItem.AppNametxtAppName · OnChange
Patch(colSystems, ThisItem, {AppName: Self.Text})2 · Vendor/Provider Name. Label lblVendor at Y 120, Text "Vendor/Provider Name". Input txtVendor at Y 144:
txtVendor · Default
ThisItem.VendortxtVendor · OnChange
Patch(colSystems, ThisItem, {Vendor: Self.Text})3 · Business Owner. Label lblOwner at Y 192, Text "Business Owner". Input txtOwner at Y 216:
txtOwner · Default
ThisItem.BizOwnertxtOwner · OnChange
Patch(colSystems, ThisItem, {BizOwner: Self.Text})4 · Application Purpose — this one is multiline. Label lblPurpose at Y 264, Text "Application Purpose". Input txtPurpose at Y 288, and additionally property dropdown → Mode → Ctrl+A → paste TextMode.MultiLine:
txtPurpose · Default
ThisItem.PurposetxtPurpose · OnChange
Patch(colSystems, ThisItem, {Purpose: Self.Text})5 · IT Custodian. Label lblCustodian at Y 336, Text "IT Custodian". Input txtCustodian at Y 360:
txtCustodian · Default
ThisItem.CustodiantxtCustodian · OnChange
Patch(colSystems, ThisItem, {Custodian: Self.Text})6 · Admin Accounts Used. Label lblAdminAccts at Y 408, Text "Admin Accounts Used". Input txtAdminAccts at Y 432:
txtAdminAccts · Default
ThisItem.AdminAcctstxtAdminAccts · OnChange
Patch(colSystems, ThisItem, {AdminAccts: Self.Text})7 · Permissions / Access Levels — multiline again. Label lblPermissions at Y 480, Text "Permissions / Access Levels". Input txtPermissions at Y 504, Mode → Ctrl+A → paste TextMode.MultiLine:
txtPermissions · Default
ThisItem.PermissionstxtPermissions · OnChange
Patch(colSystems, ThisItem, {Permissions: Self.Text})Default reads the row's stored value; OnChange writes edits straight back into colSystems. Because both use ThisItem/Self, the formulas are identical in every row and every field except the field name — and the collection is always up to date, no matter what the gallery does with its on-screen controls.colSystems: the value is in the collection.A8Right column — three inputs and four dropdowns
Same drill, right half of the card: everything at X 676 · Width 630, labels Height 20, inputs Height 40. Text values go in the same way as A7 (property dropdown → Text → Ctrl+A → paste, quotes included). Four of these are Drop down controls (+ Insert → search Drop down) — set each one's properties in this order: Items → AllowEmptySelection → Default → OnChange.
1 · Support / Vendor Contact. Label lblSupport at Y 48, Text "Support / Vendor Contact". Text input txtSupport at Y 72:
txtSupport · Default
ThisItem.SupportContacttxtSupport · OnChange
Patch(colSystems, ThisItem, {SupportContact: Self.Text})2 · IAM Role — first dropdown. Label lblIAMRole at Y 120, Text "IAM Role". Drop down drpIAMRole at Y 144. Set Items first (box below), then property dropdown → AllowEmptySelection → Ctrl+A → type true, then Default and OnChange:
drpIAMRole · Items
colIAMRolesdrpIAMRole · Default
ThisItem.IAMRoledrpIAMRole · OnChange
Patch(colSystems, ThisItem, {IAMRole: Self.Selected.Value})3 · Access Link. Label lblAccessLink at Y 192, Text "Access Link". Text input txtAccessLink at Y 216:
txtAccessLink · Default
ThisItem.AccessLinktxtAccessLink · OnChange
Patch(colSystems, ThisItem, {AccessLink: Self.Text})4 · Division. Label lblDivision at Y 264, Text "Division". Drop down drpDivision at Y 288, AllowEmptySelection true:
drpDivision · Items
colDivisionsdrpDivision · Default
ThisItem.DivisiondrpDivision · OnChange
Patch(colSystems, ThisItem, {Division: Self.Selected.Value})5 · Status. Label lblStatus at Y 336, Text "Status". Drop down drpStatus at Y 360, AllowEmptySelection true:
drpStatus · Items
colStatusValuesdrpStatus · Default
ThisItem.StatusdrpStatus · OnChange
Patch(colSystems, ThisItem, {Status: Self.Selected.Value})6 · Handover Status. Label lblHandover at Y 408, Text "Handover Status". Drop down drpHandover at Y 432, AllowEmptySelection true:
drpHandover · Items
colHandoverValuesdrpHandover · Default
ThisItem.HandoverdrpHandover · OnChange
Patch(colSystems, ThisItem, {Handover: Self.Selected.Value})7 · Number of Accounts. Label lblNumAccts at Y 480, Text "Number of Accounts". Text input txtNumAccts at Y 504, and additionally property dropdown → Format → Ctrl+A → paste TextFormat.Number:
txtNumAccts · Default
ThisItem.NumAcctstxtNumAccts · OnChange
Patch(colSystems, ThisItem, {NumAccts: Self.Text})AllowEmptySelection is true with a blank Default. Skip it and every new row is born with "Manage" / "Operations & Administration" pre-picked — which quietly defeats the mandatory-field validation coming in Part 2.A9Footer bar — Add System and the row count
Back out of the gallery template first — click empty canvas or press Esc, and check the breadcrumb: the next three controls belong to scrMain, not the template.
- + Insert → search
Rectangle→ renamerecFooter→ X0· Y692· Width1366· Height76→ Fill:gblColorInk(property dropdown → Fill → Ctrl+A → paste). - + Insert → search
Button→ renamebtnAddSystem→ X24· Y710· Width200· Height40→ Text:"+ Add System"(property dropdown → Text → Ctrl+A → paste). Property dropdown → OnSelect → Ctrl+A → paste:
btnAddSystem · OnSelect
Collect(colSystems, {RowID: GUID(), SeqNo: gblNextSeq, AppName: "", Vendor: "", BizOwner: "", Purpose: "", Custodian: "", AdminAccts: "", Permissions: "", SupportContact: "", IAMRole: "", AccessLink: "", Division: "", Status: "", Handover: "", NumAccts: ""});
Set(gblNextSeq, gblNextSeq + 1)- + Insert → search
Text label→ renamelblSystemCount→ X240· Y716· Width420· Height28→ Color:Color.White(property dropdown → Color → Ctrl+A → paste). Then property dropdown → Text → Ctrl+A → paste:
lblSystemCount · Text
CountRows(colSystems) & " system(s) in this declaration"A10The smoke test — prove the architecture
Five minutes that buy total confidence in everything Parts 2 and 3 build on. Press F5 (Preview):
- Click + Add System twice — three cards: System 1, 2, 3.
- Give each row a distinct Application Name —
Alpha,Bravo,Charlie— and fill a couple more fields in each, including a dropdown pick. - Scroll test: scroll the gallery so System 1 leaves the screen, then scroll back. Every value is still there.
- Delete-the-middle test: click Delete Row on System 2 (Bravo). Two cards remain — System 1 still says Alpha, System 3 still says Charlie. Nothing shifted, nothing bled between rows.
- Leave Preview (Esc). Left rail → Variables → Collections →
colSystems: the surviving two rows, exactly as typed. Type one more character in any field and watch the collection update on the next refresh — every keystroke lands in the collection, not just on screen.
colSystems only, which you have just watched stay correct through both.