Approval Workflow

Medium 20 min setup 6 components
Download .msapp

A manager approval queue with KPI cards, status tabs, and per-request approve / reject / return actions that require a reason. Every decision is written to an Activity Timeline of the request’s history. Sidebar and bottom nav make it work on desktop and mobile.

Two parts to paste. This template needs both the Screen YAML and the App.Formulas — without the formulas the screen renders blank. Copy both below, or just download the .msapp to skip the paste.

Preview

Interactive preview. The actual template runs natively in Power Apps.

Included in this template

Pending KPIs

Count, total value, approved this month

Status tabs

Segmented control with live per-status counts

Approval queue

Filtered, newest-first request list

Decision dialog

Approve / reject / return with a reason

Decision history

Every action written to an Activity Timeline

Mobile-ready

Sidebar, bottom nav, and mobile sheet

Components Used

This template uses these components. Install them before importing the screen YAML.

Code

Paste into the Screens tab in Power Apps Studio (Tree view → Screens → paste YAML). Collections are seeded in the screen's OnVisible.
Screens:
  scrApprovals:
    Properties:
      Fill: =RGBA(249, 250, 251, 1)
      LoadingSpinnerColor: =RGBA(37, 99, 235, 1)
      OnVisible: |-
        =// ============================================================
        //  Approvals — demo data + screen state
        //  Seeding is gated on gblApSeedVersion, not IsEmpty, so a session
        //  holding an older column shape is reseeded instead of silently kept.
        //  Swap each ClearCollect for a Filter against your real source.
        // ============================================================
        If(
            gblApSeedVersion <> "2026-07-27",
            ClearCollect(colApRequests,
                {ReqID:"PO-1042", Title:"Design tooling annual renewal",      Requester:"Sarah Chen",    Dept:"Marketing",  Amount:2480, Category:"Software",  SubmittedOn:DateAdd(Today(),-1,TimeUnit.Days), Justification:"Annual renewal of design tooling licenses for the 6-person creative team.",     Status:"Pending",  DecidedBy:"", DecidedOn:Blank(), DecisionNote:"", Selected:false},
                {ReqID:"EXP-318", Title:"Newark site visit expenses",         Requester:"James Wilson",  Dept:"Field Ops",  Amount:640,  Category:"Travel",    SubmittedOn:DateAdd(Today(),-1,TimeUnit.Days), Justification:"Site visit mileage and overnight stay, Newark inspection.",                       Status:"Pending",  DecidedBy:"", DecidedOn:Blank(), DecisionNote:"", Selected:false},
                {ReqID:"PO-1043", Title:"HVAC compressor replacement",        Requester:"Maria Garcia",  Dept:"Facilities", Amount:5120, Category:"Equipment", SubmittedOn:DateAdd(Today(),-2,TimeUnit.Days), Justification:"Replacement HVAC compressor for warehouse B, vendor quote attached.",             Status:"Pending",  DecidedBy:"", DecidedOn:Blank(), DecisionNote:"", Selected:false},
                {ReqID:"EXP-319", Title:"Q2 client dinner and demo",          Requester:"David Kim",     Dept:"Sales",      Amount:1190, Category:"Client",    SubmittedOn:DateAdd(Today(),-2,TimeUnit.Days), Justification:"Q2 client dinner and demo event, 4 prospects from the Atlas account.",           Status:"Pending",  DecidedBy:"", DecidedOn:Blank(), DecisionNote:"", Selected:false},
                {ReqID:"PO-1041", Title:"Replacement laptops for onboarding", Requester:"Lisa Anderson", Dept:"IT",         Amount:3300, Category:"Hardware",  SubmittedOn:DateAdd(Today(),-3,TimeUnit.Days), Justification:"Two replacement laptops for onboarding hires starting next sprint.",              Status:"Pending",  DecidedBy:"", DecidedOn:Blank(), DecisionNote:"", Selected:false},
                {ReqID:"PO-1040", Title:"Forklift annual service",            Requester:"Robert Taylor", Dept:"Operations", Amount:1450, Category:"Services",  SubmittedOn:DateAdd(Today(),-3,TimeUnit.Days), Justification:"Scheduled annual service and certification for both warehouse forklifts.",        Status:"Pending",  DecidedBy:"", DecidedOn:Blank(), DecisionNote:"", Selected:false},
                {ReqID:"PO-1038", Title:"Quarterly safety supply restock",    Requester:"Robert Taylor", Dept:"Operations", Amount:870,  Category:"Supplies",  SubmittedOn:DateAdd(Today(),-4,TimeUnit.Days), Justification:"Quarterly safety supply restock across all four locations.",                     Status:"Approved", DecidedBy:"You", DecidedOn:DateAdd(Now(),-2,TimeUnit.Days), DecisionNote:"", Selected:false},
                {ReqID:"PO-1039", Title:"Conference room AV upgrade",         Requester:"Lisa Anderson", Dept:"IT",         Amount:4200, Category:"Equipment", SubmittedOn:DateAdd(Today(),-4,TimeUnit.Days), Justification:"Replace the projector and conferencing mics in the main meeting room.",           Status:"Returned", DecidedBy:"You", DecidedOn:DateAdd(Now(),-1,TimeUnit.Days), DecisionNote:"Need three quotes and a install date before I can sign this off.", Selected:false},
                {ReqID:"EXP-310", Title:"Trade show booth deposit",           Requester:"Emily Parker",  Dept:"Marketing",  Amount:2050, Category:"Events",    SubmittedOn:DateAdd(Today(),-5,TimeUnit.Days), Justification:"Trade show booth deposit for the autumn industry expo.",                          Status:"Rejected", DecidedBy:"You", DecidedOn:DateAdd(Now(),-3,TimeUnit.Days), DecisionNote:"Over budget for the quarter, resubmit next period.", Selected:false}
            );

            ClearCollect(colApStatus,
                {StatusKey:"Pending",  Label:"Pending",  Order:1, IsOpen:true,  PillBg:RGBA(254, 243, 199, 1), PillText:RGBA(180, 83,  9,   1)},
                {StatusKey:"Approved", Label:"Approved", Order:2, IsOpen:false, PillBg:RGBA(220, 252, 231, 1), PillText:RGBA(22,  163, 74,  1)},
                {StatusKey:"Returned", Label:"Returned", Order:3, IsOpen:false, PillBg:RGBA(224, 231, 255, 1), PillText:RGBA(55,  48,  163, 1)},
                {StatusKey:"Rejected", Label:"Rejected", Order:4, IsOpen:false, PillBg:RGBA(254, 226, 226, 1), PillText:RGBA(220, 38,  38,  1)}
            );

            ClearCollect(colApDept,
                {Dept:"Marketing",  Fill:RGBA(79,  70,  229, 1)},
                {Dept:"Field Ops",  Fill:RGBA(13,  148, 136, 1)},
                {Dept:"Facilities", Fill:RGBA(217, 119, 6,   1)},
                {Dept:"Sales",      Fill:RGBA(219, 39,  119, 1)},
                {Dept:"IT",         Fill:RGBA(37,  99,  235, 1)},
                {Dept:"Operations", Fill:RGBA(100, 116, 139, 1)},
                {Dept:"default",    Fill:RGBA(107, 114, 128, 1)}
            );

            ClearCollect(colApHistory,
                {EventTitle:"Approved", EventDescription:"PO-1038 · $870",   Author:"You", EventOn:DateAdd(Now(), -2, TimeUnit.Days), Category:"Approved", HasSubDetail:false, SubTo:"",              SubCC:"", SubPriority:"",       SubMessage:""},
                {EventTitle:"Returned", EventDescription:"PO-1039 · $4,200", Author:"You", EventOn:DateAdd(Now(), -1, TimeUnit.Days), Category:"Returned", HasSubDetail:true,  SubTo:"Lisa Anderson", SubCC:"", SubPriority:"Normal", SubMessage:"Need three quotes and a install date before I can sign this off."},
                {EventTitle:"Rejected", EventDescription:"EXP-310 · $2,050", Author:"You", EventOn:DateAdd(Now(), -3, TimeUnit.Days), Category:"Rejected", HasSubDetail:true,  SubTo:"Emily Parker",  SubCC:"", SubPriority:"Normal", SubMessage:"Over budget for the quarter, resubmit next period."}
            );

            Set(gblApSeedVersion, "2026-07-27")
        );

        // ---- screen state ----
        If(IsBlank(gblApFilter), Set(gblApFilter, nfApOpenKey));
        Set(gblApActionID, "");
        Set(gblApAction, "");
        Set(gblApActiveTab, 3);
        UpdateIf(colApRequests, Selected, {Selected: false});

        // ---- component-owned globals (contract, not renameable) ----
        Set(_cmpNavIsExpanded, true);
        Set(_cmpNavSelID, 3);
        Set(_auditFilter, Blank());

        UpdateContext({locApSheetOpen: false})
    Children:
      - cntRootAp:
          Control: GroupContainer@1.5.0
          Variant: AutoLayout
          Properties:
            DropShadow: =DropShadow.None
            Fill: =RGBA(249, 250, 251, 1)
            Height: =Parent.Height
            LayoutDirection: =LayoutDirection.Vertical
            PaddingLeft: =If(App.Width >= 1024, If(_cmpNavIsExpanded, 224, 52), 0)
            Width: =Parent.Width
          Children:
            - cntMiddleAp:
                Control: GroupContainer@1.5.0
                Variant: AutoLayout
                Properties:
                  DropShadow: =DropShadow.None
                  FillPortions: =0
                  Height: =Parent.Height
                  LayoutDirection: =LayoutDirection.Horizontal
                  Width: =Parent.Width
                Children:
                  - cntRightStackAp:
                      Control: GroupContainer@1.5.0
                      Variant: AutoLayout
                      Properties:
                        DropShadow: =DropShadow.None
                        Height: =Parent.Height
                        LayoutAlignItems: =LayoutAlignItems.Stretch
                        LayoutDirection: =LayoutDirection.Vertical
                        LayoutMinHeight: =0
                      Children:
                        - conTopBarAp:
                            Control: GroupContainer@1.5.0
                            Variant: AutoLayout
                            Properties:
                              DropShadow: =DropShadow.None
                              Fill: =RGBA(255, 255, 255, 1)
                              FillPortions: =0
                              Height: =If(App.Width < 768, 120, 66)
                              LayoutAlignItems: =If(App.Width < 768, LayoutAlignItems.Stretch, LayoutAlignItems.Center)
                              LayoutDirection: =If(App.Width < 768, LayoutDirection.Vertical, LayoutDirection.Horizontal)
                              LayoutGap: =If(App.Width < 768, 8, 12)
                              LayoutJustifyContent: =LayoutJustifyContent.SpaceBetween
                              LayoutMinHeight: =0
                              PaddingBottom: =If(App.Width < 768, 10, 0)
                              PaddingLeft: =If(App.Width < 640, 14, 22)
                              PaddingRight: =If(App.Width < 640, 14, 22)
                              PaddingTop: =If(App.Width < 768, 14, 0)
                            Children:
                              - conApTitleGroup:
                                  Control: GroupContainer@1.5.0
                                  Variant: AutoLayout
                                  Properties:
                                    DropShadow: =DropShadow.None
                                    Height: =If(App.Width < 768, 44, Parent.Height)
                                    LayoutDirection: =LayoutDirection.Vertical
                                    LayoutGap: =2
                                    LayoutJustifyContent: =LayoutJustifyContent.Center
                                    LayoutMinHeight: =0
                                    LayoutMinWidth: =0
                                  Children:
                                    - lblApTitle:
                                        Control: ModernText@1.0.0
                                        Properties:
                                          AlignInContainer: =AlignInContainer.Stretch
                                          AutoHeight: =true
                                          Color: =RGBA(17, 24, 39, 1)
                                          FontWeight: =FontWeight.Bold
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          Size: =18
                                          Text: ="Approvals"
                                    - lblApSubtitle:
                                        Control: ModernText@1.0.0
                                        Properties:
                                          AlignInContainer: =AlignInContainer.Stretch
                                          AutoHeight: =true
                                          Color: =RGBA(107, 114, 128, 1)
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          Size: =12
                                          Text: ="Purchase orders and expenses awaiting your review"
                                          Visible: =App.Width >= 640
                              - conApTopActions:
                                  Control: GroupContainer@1.5.0
                                  Variant: AutoLayout
                                  Properties:
                                    DropShadow: =DropShadow.None
                                    Height: =If(App.Width < 768, 40, Parent.Height)
                                    LayoutAlignItems: =LayoutAlignItems.Center
                                    LayoutDirection: =LayoutDirection.Horizontal
                                    LayoutGap: =8
                                    LayoutJustifyContent: =LayoutJustifyContent.End
                                    LayoutMinHeight: =0
                                    LayoutMinWidth: =0
                                  Children:
                                    - cmpApTabs:
                                        Control: CanvasComponent
                                        ComponentName: cmpSegmentedControl
                                        Properties:
                                          AlignInContainer: =AlignInContainer.Center
                                          DefaultValue: =nfApOpenKey
                                          Disabled: =false
                                          DisplayMode: ="Text"
                                          EqualWidth: =true
                                          FillPortions: =1
                                          Height: =36
                                          IconPosition: ="Left"
                                          LayoutMaxWidth: =370
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          OnChange: |-
                                            =Set(gblApFilter, cmpApTabs.SelectedValue);
                                            Set(gblApActionID, "");
                                            Set(gblApAction, "")
                                          Options: =nfApTabOptions
                                          Size: ="Small"
                                          Theme: ="Light"
                                          Width: =200
                                    - btnApHistory:
                                        Control: Button@0.0.45
                                        Properties:
                                          AlignInContainer: =AlignInContainer.Center
                                          Appearance: ='ButtonCanvas.Appearance'.Secondary
                                          Height: =36
                                          Icon: ="History"
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          OnSelect: |-
                                            =UpdateContext({locApSheetOpen: true})
                                          Text: =""
                                          Visible: =App.Width < 1024
                                          Width: =40
                        - shpApTopDivider:
                            Control: Rectangle@2.3.0
                            Properties:
                              AlignInContainer: =AlignInContainer.Stretch
                              BorderStyle: =BorderStyle.None
                              Fill: =RGBA(229, 231, 235, 1)
                              Height: =1
                              LayoutMinHeight: =1
                        - conPageAp:
                            Control: GroupContainer@1.5.0
                            Variant: AutoLayout
                            Properties:
                              DropShadow: =DropShadow.None
                              LayoutDirection: =LayoutDirection.Vertical
                              LayoutGap: =14
                              LayoutMinHeight: =0
                              LayoutOverflowY: =LayoutOverflow.Scroll
                              PaddingBottom: =16
                              PaddingLeft: =If(App.Width < 640, 14, 22)
                              PaddingRight: =If(App.Width < 640, 14, 22)
                              PaddingTop: =16
                            Children:
                              - conApStats:
                                  Control: GroupContainer@1.5.0
                                  Variant: AutoLayout
                                  Properties:
                                    DropShadow: =DropShadow.None
                                    FillPortions: =0
                                    Height: =cmpApKpi.Height
                                    LayoutDirection: =LayoutDirection.Vertical
                                    LayoutMinHeight: =0
                                  Children:
                                    - cmpApKpi:
                                        Control: CanvasComponent
                                        ComponentName: cmpKPI
                                        Properties:
                                          AlignInContainer: =AlignInContainer.Stretch
                                          AnimationEffect: ="Pop"
                                          ColumnsLayout: |-
                                            ={
                                                Mobile: 2,
                                                Tablet: 3,
                                                Desktop: 3,
                                                MobileBreakpoint:  IfError(Index(App.SizeBreakpoints, 1).Value, 640),
                                                TabletBreakpoint:  IfError(Index(App.SizeBreakpoints, 2).Value, 1024),
                                                DesktopBreakpoint: IfError(Index(App.SizeBreakpoints, 3).Value, 1366)
                                            }
                                          Data: |-
                                            =Table(
                                                {ID: 1, Icon: "Clock",  Value: nfApPendingCount,      Label: "Pending review",      PercentChange: 0, PercentLabel: "", IconBg: "#EEF2FF", IconColor: "#4F46E5", SparklineData: "", isHidden: false},
                                                {ID: 2, Icon: "Dollar", Value: nfApPendingValue,      Label: "Pending value",       PercentChange: 0, PercentLabel: "", IconBg: "#FEF3C7", IconColor: "#B45309", SparklineData: "", isHidden: false},
                                                {ID: 3, Icon: "Target", Value: nfApApprovedThisMonth, Label: "Approved this month", PercentChange: 0, PercentLabel: "", IconBg: "#DCFCE7", IconColor: "#16A34A", SparklineData: "", isHidden: App.Width < 640}
                                            )
                                          Height: |-
                                            =With(
                                                {
                                                    _cols:  If(App.Width < 640, 2, 3),
                                                    _cards: CountRows(Filter(cmpApKpi.Data, !IfError(isHidden, false)))
                                                },
                                                RoundUp(_cards / _cols, 0) * (96 + 12) + 12
                                            )
                                          Icons: |-
                                            =Table(
                                                {Name: "Clock",  SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='COLOR' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><polyline points='12 6 12 12 16 14'/></svg>"},
                                                {Name: "Dollar", SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='COLOR' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='12' y1='1' x2='12' y2='23'/><path d='M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6'/></svg>"},
                                                {Name: "Target", SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='COLOR' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><circle cx='12' cy='12' r='6'/><circle cx='12' cy='12' r='2'/></svg>"}
                                            )
                                          IsLoading: =IsEmpty(colApRequests)
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          OnCardClick: |-
                                            =Switch(
                                                ClickedItem.ID,
                                                1, Set(gblApFilter, nfApOpenKey),
                                                3, Set(gblApFilter, "Approved")
                                            )
                                          Style: ="Minimal"
                                          StyleConfig: |-
                                            ={
                                                colors: {
                                                    cardBg:        ColorValue("#FFFFFF"),
                                                    border:        ColorValue("#E5E7EB"),
                                                    text:          ColorValue("#111827"),
                                                    textMuted:     ColorValue("#6B7280"),
                                                    positive:      ColorValue("#22C55E"),
                                                    negative:      ColorValue("#EF4444"),
                                                    neutral:       ColorValue("#9E9E9E"),
                                                    skeletonBase:  ColorValue("#E5E7EB"),
                                                    skeletonShine: ColorValue("#F3F4F6")
                                                },
                                                space:  {xs: 4, sm: 8, md: 12, lg: 16, xl: 24},
                                                radius: {md: 8, lg: 12},
                                                type: {
                                                    value: {size: 32, sizeCompact: 22},
                                                    label: {size: 11},
                                                    body:  {size: 12}
                                                },
                                                heights: {statsCardMax: 190},
                                                abbreviateThreshold: 0
                                            }
                                          Width: =Parent.Width
                              - conApSelBar:
                                  Control: GroupContainer@1.5.0
                                  Variant: AutoLayout
                                  Properties:
                                    BorderColor: =RGBA(191, 219, 254, 1)
                                    BorderThickness: =1
                                    DropShadow: =DropShadow.None
                                    Fill: =RGBA(239, 246, 255, 1)
                                    FillPortions: =0
                                    Height: =52
                                    LayoutAlignItems: =LayoutAlignItems.Center
                                    LayoutDirection: =LayoutDirection.Horizontal
                                    LayoutGap: =8
                                    LayoutMinHeight: =0
                                    PaddingLeft: =16
                                    PaddingRight: =12
                                    RadiusBottomLeft: =12
                                    RadiusBottomRight: =12
                                    RadiusTopLeft: =12
                                    RadiusTopRight: =12
                                    Visible: =gblApFilter = nfApOpenKey && nfApSelectedCount > 0
                                  Children:
                                    - lblApSelCount:
                                        Control: ModernText@1.0.0
                                        Properties:
                                          AutoHeight: =true
                                          Color: =RGBA(30, 64, 175, 1)
                                          FillPortions: =1
                                          FontWeight: =FontWeight.Semibold
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          Size: =13
                                          Text: |-
                                            =nfApSelectedCount & " selected · " &
                                            Text(Coalesce(Sum(Filter(colApRequests, Status = nfApOpenKey, Selected), Amount), 0), "[$-en-US]$#,##0")
                                    - btnApSelectAll:
                                        Control: Button@0.0.45
                                        Properties:
                                          Appearance: ='ButtonCanvas.Appearance'.Subtle
                                          Height: =34
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          OnSelect: |-
                                            =UpdateIf(
                                                colApRequests,
                                                Status = nfApOpenKey,
                                                {Selected: nfApSelectedCount < nfApPendingCount}
                                            )
                                          Text: =If(nfApSelectedCount < nfApPendingCount, "Select all", "Clear")
                                    - btnApBulkApprove:
                                        Control: Button@0.0.45
                                        Properties:
                                          Appearance: ='ButtonCanvas.Appearance'.Primary
                                          Height: =34
                                          Icon: ="Checkmark"
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          OnSelect: |-
                                            =// SWAP POINT: replace both statements with a single flow call that
                                            // owns the transition, e.g. flowApproveBatch.Run(JSON(Filter(...)))
                                            ForAll(
                                                Filter(colApRequests, Status = nfApOpenKey, Selected) As _r,
                                                Collect(colApHistory,
                                                    {
                                                        EventTitle: "Approved",
                                                        EventDescription: _r.ReqID & " · " & Text(_r.Amount, "[$-en-US]$#,##0"),
                                                        Author: "You",
                                                        EventOn: Now(),
                                                        Category: "Approved",
                                                        HasSubDetail: false,
                                                        SubTo: "", SubCC: "", SubPriority: "", SubMessage: ""
                                                    }
                                                )
                                            );
                                            UpdateIf(
                                                colApRequests,
                                                Status = nfApOpenKey && Selected,
                                                {
                                                    Status: "Approved",
                                                    DecidedBy: "You",
                                                    DecidedOn: Now(),
                                                    Selected: false
                                                }
                                            )
                                          Text: ="Approve " & nfApSelectedCount
                                          Width: =128
                              - conApGrid:
                                  Control: GroupContainer@1.5.0
                                  Variant: AutoLayout
                                  Properties:
                                    DropShadow: =DropShadow.None
                                    LayoutAlignItems: =LayoutAlignItems.Stretch
                                    LayoutDirection: =LayoutDirection.Horizontal
                                    LayoutGap: =14
                                    LayoutMinHeight: =0
                                  Children:
                                    - conApQueue:
                                        Control: GroupContainer@1.5.0
                                        Variant: AutoLayout
                                        Properties:
                                          DropShadow: =DropShadow.None
                                          FillPortions: =2
                                          LayoutDirection: =LayoutDirection.Vertical
                                          LayoutMinHeight: =300
                                          LayoutMinWidth: =0
                                        Children:
                                          - galApQueue:
                                              Control: Gallery@2.15.0
                                              Variant: VariableHeight
                                              Properties:
                                                DelayItemLoading: =false
                                                Items: =nfApFiltered
                                                LayoutMinHeight: =0
                                                LoadingSpinner: =LoadingSpinner.None
                                                TemplatePadding: =0
                                                TemplateSize: =210
                                                Visible: =nfApCount > 0
                                                Width: =Parent.Width
                                              Children:
                                                - lblApCardHeight:
                                                    Control: Label@2.5.1
                                                    Properties:
                                                      Height: =1
                                                      OnSelect: =Select(Parent)
                                                      Text: |-
                                                        =shpApFootDiv.Y +
                                                        If(Parent.TemplateWidth < 520, 92, 58)
                                                      Visible: =false
                                                      Width: =1
                                                - conApCard:
                                                    Control: GroupContainer@1.5.0
                                                    Variant: ManualLayout
                                                    Properties:
                                                      BorderColor: =RGBA(229, 231, 235, 1)
                                                      BorderThickness: =1
                                                      DropShadow: =DropShadow.None
                                                      Fill: =RGBA(255, 255, 255, 1)
                                                      Height: =210
                                                      RadiusBottomLeft: =12
                                                      RadiusBottomRight: =12
                                                      RadiusTopLeft: =12
                                                      RadiusTopRight: =12
                                                      Width: =Parent.TemplateWidth - 4
                                                      X: =1
                                                    Children:
                                                      - conApSelBox:
                                                          Control: GroupContainer@1.5.0
                                                          Variant: ManualLayout
                                                          Properties:
                                                            BorderColor: =If(ThisItem.Selected, RGBA(37, 99, 235, 1), RGBA(203, 213, 225, 1))
                                                            BorderThickness: =1.5
                                                            DropShadow: =DropShadow.None
                                                            Fill: =If(ThisItem.Selected, RGBA(37, 99, 235, 1), RGBA(255, 255, 255, 1))
                                                            Height: =20
                                                            RadiusBottomLeft: =5
                                                            RadiusBottomRight: =5
                                                            RadiusTopLeft: =5
                                                            RadiusTopRight: =5
                                                            Visible: =ThisItem.Status = nfApOpenKey
                                                            Width: =20
                                                            X: =16
                                                            Y: =20
                                                          Children:
                                                            - imgApCheck:
                                                                Control: Image@2.2.3
                                                                Properties:
                                                                  Height: =12
                                                                  Image: ="data:image/svg+xml," & EncodeUrl("<svg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>")
                                                                  Visible: =ThisItem.Selected
                                                                  Width: =12
                                                                  X: =4
                                                                  Y: =4
                                                      - btnApSelOverlay:
                                                          Control: Classic/Button@2.2.0
                                                          Properties:
                                                            BorderColor: =RGBA(0, 0, 0, 0)
                                                            BorderStyle: =BorderStyle.None
                                                            Color: =RGBA(0, 0, 0, 0)
                                                            Fill: =RGBA(0, 0, 0, 0)
                                                            Height: =32
                                                            HoverBorderColor: =RGBA(0, 0, 0, 0)
                                                            HoverColor: =RGBA(0, 0, 0, 0)
                                                            HoverFill: =RGBA(0, 0, 0, 0.04)
                                                            OnSelect: |-
                                                              =UpdateIf(
                                                                  colApRequests,
                                                                  ReqID = ThisItem.ReqID,
                                                                  {Selected: !Selected}
                                                              )
                                                            PressedBorderColor: =RGBA(0, 0, 0, 0)
                                                            PressedColor: =RGBA(0, 0, 0, 0)
                                                            PressedFill: =RGBA(0, 0, 0, 0.08)
                                                            RadiusBottomLeft: =16
                                                            RadiusBottomRight: =16
                                                            RadiusTopLeft: =16
                                                            RadiusTopRight: =16
                                                            Text: =""
                                                            Visible: =ThisItem.Status = nfApOpenKey
                                                            Width: =32
                                                            X: =10
                                                            Y: =14
                                                      - conApAvatar:
                                                          Control: GroupContainer@1.5.0
                                                          Variant: ManualLayout
                                                          Properties:
                                                            DropShadow: =DropShadow.None
                                                            Fill: |-
                                                              =Coalesce(
                                                                  LookUp(colApDept As _d, _d.Dept = ThisItem.Dept, _d.Fill),
                                                                  LookUp(colApDept As _d, _d.Dept = "default", _d.Fill)
                                                              )
                                                            Height: =40
                                                            RadiusBottomLeft: =20
                                                            RadiusBottomRight: =20
                                                            RadiusTopLeft: =20
                                                            RadiusTopRight: =20
                                                            Width: =40
                                                            X: =If(ThisItem.Status = nfApOpenKey, 48, 16)
                                                            Y: =14
                                                          Children:
                                                            - lblApInitials:
                                                                Control: Label@2.5.1
                                                                Properties:
                                                                  Align: =Align.Center
                                                                  Color: =RGBA(255, 255, 255, 1)
                                                                  Font: =Font.'Segoe UI'
                                                                  FontWeight: =FontWeight.Bold
                                                                  Size: =12
                                                                  Text: |-
                                                                    =Upper(
                                                                        Concat(
                                                                            FirstN(Split(ThisItem.Requester, " "), 2),
                                                                            Left(Value, 1)
                                                                        )
                                                                    )
                                                                  Width: =40
                                                      - lblApReqName:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            Color: =RGBA(17, 24, 39, 1)
                                                            Font: =Font.'Segoe UI'
                                                            FontWeight: =FontWeight.Semibold
                                                            Height: =20
                                                            PaddingLeft: =0
                                                            Size: =12
                                                            Text: =ThisItem.Requester
                                                            Width: =Parent.Width - conApAvatar.X - 160
                                                            Wrap: =false
                                                            X: =conApAvatar.X + 52
                                                            Y: =15
                                                      - lblApReqDept:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            Color: =RGBA(107, 114, 128, 1)
                                                            Font: =Font.'Segoe UI'
                                                            Height: =18
                                                            PaddingLeft: =0
                                                            Size: =11
                                                            Text: =ThisItem.Dept
                                                            Width: =Parent.Width - conApAvatar.X - 160
                                                            Wrap: =false
                                                            X: =conApAvatar.X + 52
                                                            Y: =35
                                                      - lblApAmount:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            Align: =Align.Right
                                                            Color: =RGBA(17, 24, 39, 1)
                                                            Font: =Font.'Segoe UI'
                                                            FontWeight: =FontWeight.Bold
                                                            Height: =28
                                                            PaddingRight: =0
                                                            Size: =17
                                                            Text: =Text(ThisItem.Amount, "[$-en-US]$#,##0")
                                                            Width: =120
                                                            Wrap: =false
                                                            X: =Parent.Width - 136
                                                            Y: =20
                                                      - lblApCardTitle:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            AutoHeight: =true
                                                            Color: =RGBA(17, 24, 39, 1)
                                                            Font: =Font.'Segoe UI'
                                                            FontWeight: =FontWeight.Semibold
                                                            Height: =22
                                                            PaddingBottom: =0
                                                            PaddingLeft: =0
                                                            PaddingRight: =0
                                                            PaddingTop: =0
                                                            Text: =ThisItem.Title
                                                            VerticalAlign: =VerticalAlign.Top
                                                            Width: =Parent.Width - 32
                                                            X: =16
                                                            Y: =66
                                                      - conApChip:
                                                          Control: GroupContainer@1.5.0
                                                          Variant: ManualLayout
                                                          Properties:
                                                            DropShadow: =DropShadow.None
                                                            Fill: =RGBA(243, 244, 246, 1)
                                                            Height: =22
                                                            RadiusBottomLeft: =11
                                                            RadiusBottomRight: =11
                                                            RadiusTopLeft: =11
                                                            RadiusTopRight: =11
                                                            Width: =Len(ThisItem.Category) * 6.4 + 20
                                                            X: =16
                                                            Y: =lblApCardTitle.Y + lblApCardTitle.Height + 8
                                                          Children:
                                                            - lblApChipText:
                                                                Control: Label@2.5.1
                                                                Properties:
                                                                  Align: =Align.Center
                                                                  Color: =RGBA(75, 85, 99, 1)
                                                                  Font: =Font.'Segoe UI'
                                                                  FontWeight: =FontWeight.Semibold
                                                                  Height: =22
                                                                  PaddingLeft: =0
                                                                  PaddingRight: =0
                                                                  Size: =10
                                                                  Text: =ThisItem.Category
                                                                  Width: =Parent.Width
                                                                  Wrap: =false
                                                      - lblApReqCode:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            Color: =RGBA(107, 114, 128, 1)
                                                            Font: =Font.'Segoe UI'
                                                            Height: =22
                                                            PaddingLeft: =0
                                                            Size: =11
                                                            Text: =ThisItem.ReqID
                                                            Width: =92
                                                            Wrap: =false
                                                            X: =conApChip.X + conApChip.Width + 10
                                                            Y: =conApChip.Y
                                                      - conApWaitPill:
                                                          Control: GroupContainer@1.5.0
                                                          Variant: ManualLayout
                                                          Properties:
                                                            DropShadow: =DropShadow.None
                                                            Fill: |-
                                                              =Coalesce(
                                                                  LookUp(colApStatus As _s, _s.StatusKey = ThisItem.Status, _s.PillBg),
                                                                  RGBA(243, 244, 246, 1)
                                                              )
                                                            Height: =22
                                                            RadiusBottomLeft: =11
                                                            RadiusBottomRight: =11
                                                            RadiusTopLeft: =11
                                                            RadiusTopRight: =11
                                                            Visible: =ThisItem.Status = nfApOpenKey
                                                            Width: =66
                                                            X: =lblApReqCode.X + 100
                                                            Y: =conApChip.Y
                                                          Children:
                                                            - lblApWaitPill:
                                                                Control: Label@2.5.1
                                                                Properties:
                                                                  Align: =Align.Center
                                                                  Color: |-
                                                                    =Coalesce(
                                                                        LookUp(colApStatus As _s, _s.StatusKey = ThisItem.Status, _s.PillText),
                                                                        RGBA(75, 85, 99, 1)
                                                                    )
                                                                  Font: =Font.'Segoe UI'
                                                                  FontWeight: =FontWeight.Bold
                                                                  Height: =22
                                                                  PaddingLeft: =0
                                                                  PaddingRight: =0
                                                                  Size: =10
                                                                  Text: =ThisItem.Status
                                                                  Width: =66
                                                      - lblApJust:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            AutoHeight: =true
                                                            Color: =RGBA(75, 85, 99, 1)
                                                            Font: =Font.'Segoe UI'
                                                            Height: =20
                                                            PaddingBottom: =0
                                                            PaddingLeft: =0
                                                            PaddingRight: =0
                                                            PaddingTop: =0
                                                            Size: =11
                                                            Text: =ThisItem.Justification
                                                            VerticalAlign: =VerticalAlign.Top
                                                            Width: =Parent.Width - 32
                                                            X: =16
                                                            Y: =conApChip.Y + 30
                                                      - shpApFootDiv:
                                                          Control: Rectangle@2.3.0
                                                          Properties:
                                                            BorderStyle: =BorderStyle.None
                                                            Fill: =RGBA(243, 244, 246, 1)
                                                            Height: =1
                                                            Width: =Parent.Width - 32
                                                            X: =16
                                                            Y: =lblApJust.Y + lblApJust.Height + 12
                                                      - lblApSubmitted:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            Color: =RGBA(107, 114, 128, 1)
                                                            Font: =Font.'Segoe UI'
                                                            Height: =26
                                                            PaddingLeft: =0
                                                            Size: =11
                                                            Text: |-
                                                              =With(
                                                                  {_d: DateDiff(ThisItem.SubmittedOn, Today(), TimeUnit.Days)},
                                                                  Switch(
                                                                      true,
                                                                      _d <= 0, "Submitted today",
                                                                      _d = 1,  "Submitted 1 day ago",
                                                                               "Submitted " & _d & " days ago"
                                                                  )
                                                              )
                                                            Visible: =ThisItem.Status = nfApOpenKey
                                                            Width: =Parent.Width - 32
                                                            Wrap: =false
                                                            X: =16
                                                            Y: =shpApFootDiv.Y + If(Parent.Width < 520, 8, 12)
                                                      - btnApSendBack:
                                                          Control: Button@0.0.45
                                                          Properties:
                                                            Appearance: ='ButtonCanvas.Appearance'.Subtle
                                                            FontColor: =RGBA(55, 48, 163, 1)
                                                            Height: =34
                                                            OnSelect: |-
                                                              =Set(gblApActionID, ThisItem.ReqID);
                                                              Set(gblApAction, "Return")
                                                            Text: ="Send back"
                                                            Visible: =ThisItem.Status = nfApOpenKey
                                                            Width: =If(Parent.Width < 520, (Parent.Width - 48) / 3, 100)
                                                            X: =If(Parent.Width < 520, 16, Parent.Width - 318)
                                                            Y: =shpApFootDiv.Y + If(Parent.Width < 520, 42, 12)
                                                      - btnApReject:
                                                          Control: Button@0.0.45
                                                          Properties:
                                                            Appearance: ='ButtonCanvas.Appearance'.Secondary
                                                            FontColor: =RGBA(220, 38, 38, 1)
                                                            Height: =34
                                                            OnSelect: |-
                                                              =Set(gblApActionID, ThisItem.ReqID);
                                                              Set(gblApAction, "Reject")
                                                            Text: ="Reject"
                                                            Visible: =ThisItem.Status = nfApOpenKey
                                                            Width: =If(Parent.Width < 520, (Parent.Width - 48) / 3, 94)
                                                            X: =If(Parent.Width < 520, 24 + (Parent.Width - 48) / 3, Parent.Width - 212)
                                                            Y: =shpApFootDiv.Y + If(Parent.Width < 520, 42, 12)
                                                      - btnApApprove:
                                                          Control: Button@0.0.45
                                                          Properties:
                                                            Appearance: ='ButtonCanvas.Appearance'.Primary
                                                            Height: =34
                                                            OnSelect: |-
                                                              =// SWAP POINT: replace with a flow call that owns the transition
                                                              // and appends history, e.g. flowApprove.Run(ThisItem.ReqID)
                                                              Collect(colApHistory,
                                                                  {
                                                                      EventTitle: "Approved",
                                                                      EventDescription: ThisItem.ReqID & " · " & Text(ThisItem.Amount, "[$-en-US]$#,##0"),
                                                                      Author: "You",
                                                                      EventOn: Now(),
                                                                      Category: "Approved",
                                                                      HasSubDetail: false,
                                                                      SubTo: "", SubCC: "", SubPriority: "", SubMessage: ""
                                                                  }
                                                              );
                                                              UpdateIf(
                                                                  colApRequests,
                                                                  ReqID = ThisItem.ReqID,
                                                                  {
                                                                      Status: "Approved",
                                                                      DecidedBy: "You",
                                                                      DecidedOn: Now(),
                                                                      Selected: false
                                                                  }
                                                              )
                                                            Text: ="Approve"
                                                            Visible: =ThisItem.Status = nfApOpenKey
                                                            Width: =If(Parent.Width < 520, (Parent.Width - 48) / 3, 98)
                                                            X: =If(Parent.Width < 520, 32 + 2 * ((Parent.Width - 48) / 3), Parent.Width - 112)
                                                            Y: =shpApFootDiv.Y + If(Parent.Width < 520, 42, 12)
                                                      - conApDecidedPill:
                                                          Control: GroupContainer@1.5.0
                                                          Variant: ManualLayout
                                                          Properties:
                                                            DropShadow: =DropShadow.None
                                                            Fill: |-
                                                              =Coalesce(
                                                                  LookUp(colApStatus As _s, _s.StatusKey = ThisItem.Status, _s.PillBg),
                                                                  RGBA(243, 244, 246, 1)
                                                              )
                                                            Height: =24
                                                            RadiusBottomLeft: =12
                                                            RadiusBottomRight: =12
                                                            RadiusTopLeft: =12
                                                            RadiusTopRight: =12
                                                            Visible: =ThisItem.Status <> nfApOpenKey
                                                            Width: =78
                                                            X: =16
                                                            Y: =shpApFootDiv.Y + 17
                                                          Children:
                                                            - lblApDecidedPill:
                                                                Control: Label@2.5.1
                                                                Properties:
                                                                  Align: =Align.Center
                                                                  Color: |-
                                                                    =Coalesce(
                                                                        LookUp(colApStatus As _s, _s.StatusKey = ThisItem.Status, _s.PillText),
                                                                        RGBA(75, 85, 99, 1)
                                                                    )
                                                                  Font: =Font.'Segoe UI'
                                                                  FontWeight: =FontWeight.Bold
                                                                  Height: =24
                                                                  PaddingLeft: =0
                                                                  PaddingRight: =0
                                                                  Size: =10
                                                                  Text: =ThisItem.Status
                                                                  Width: =78
                                                      - lblApDecidedBy:
                                                          Control: Label@2.5.1
                                                          Properties:
                                                            AutoHeight: =true
                                                            Color: =RGBA(75, 85, 99, 1)
                                                            Font: =Font.'Segoe UI'
                                                            Height: =20
                                                            PaddingBottom: =0
                                                            PaddingLeft: =0
                                                            PaddingRight: =0
                                                            PaddingTop: =0
                                                            Size: =11
                                                            Text: |-
                                                              ="by " & ThisItem.DecidedBy & " · " &
                                                              Text(ThisItem.DecidedOn, "[$-en-US]mmm d, yyyy") &
                                                              If(
                                                                  IsBlank(ThisItem.DecisionNote),
                                                                  "",
                                                                  Char(10) & "Note: " & ThisItem.DecisionNote
                                                              )
                                                            VerticalAlign: =VerticalAlign.Top
                                                            Visible: =ThisItem.Status <> nfApOpenKey
                                                            Width: =Parent.Width - 122
                                                            X: =102
                                                            Y: =shpApFootDiv.Y + 18
                                          - conApEmpty:
                                              Control: GroupContainer@1.5.0
                                              Variant: AutoLayout
                                              Properties:
                                                BorderColor: =RGBA(229, 231, 235, 1)
                                                BorderThickness: =1
                                                DropShadow: =DropShadow.None
                                                Fill: =RGBA(255, 255, 255, 1)
                                                LayoutAlignItems: =LayoutAlignItems.Center
                                                LayoutDirection: =LayoutDirection.Vertical
                                                LayoutGap: =6
                                                LayoutJustifyContent: =LayoutJustifyContent.Center
                                                LayoutMinHeight: =0
                                                RadiusBottomLeft: =12
                                                RadiusBottomRight: =12
                                                RadiusTopLeft: =12
                                                RadiusTopRight: =12
                                                Visible: =nfApCount = 0
                                              Children:
                                                - lblApEmptyHead:
                                                    Control: ModernText@1.0.0
                                                    Properties:
                                                      AutoHeight: =true
                                                      Color: =RGBA(17, 24, 39, 1)
                                                      FontWeight: =FontWeight.Semibold
                                                      LayoutMinHeight: =0
                                                      LayoutMinWidth: =0
                                                      Size: =14
                                                      Text: ="Nothing " & Lower(gblApFilter) & " right now"
                                                - lblApEmptyBody:
                                                    Control: ModernText@1.0.0
                                                    Properties:
                                                      Align: =Align.Center
                                                      AutoHeight: =true
                                                      Color: =RGBA(107, 114, 128, 1)
                                                      LayoutMinHeight: =0
                                                      LayoutMinWidth: =0
                                                      Size: =12
                                                      Text: ="Decisions you make land in the activity trail on the right."
                                    - conApActivity:
                                        Control: GroupContainer@1.5.0
                                        Variant: AutoLayout
                                        Properties:
                                          BorderColor: =RGBA(229, 231, 235, 1)
                                          BorderThickness: =1
                                          DropShadow: =DropShadow.None
                                          Fill: =RGBA(255, 255, 255, 1)
                                          LayoutDirection: =LayoutDirection.Vertical
                                          LayoutMinHeight: =0
                                          LayoutMinWidth: =0
                                          PaddingBottom: =12
                                          PaddingLeft: =18
                                          PaddingRight: =6
                                          PaddingTop: =16
                                          RadiusBottomLeft: =12
                                          RadiusBottomRight: =12
                                          RadiusTopLeft: =12
                                          RadiusTopRight: =12
                                          Visible: =App.Width >= 1024
                                        Children:
                                          - lblApActivityHead:
                                              Control: ModernText@1.0.0
                                              Properties:
                                                AlignInContainer: =AlignInContainer.Stretch
                                                AutoHeight: =true
                                                Color: =RGBA(17, 24, 39, 1)
                                                FontWeight: =FontWeight.Bold
                                                LayoutMinHeight: =0
                                                LayoutMinWidth: =0
                                                Size: =14
                                                Text: ="Activity"
                                          - lblApActivitySub:
                                              Control: ModernText@1.0.0
                                              Properties:
                                                AlignInContainer: =AlignInContainer.Stretch
                                                AutoHeight: =true
                                                Color: =RGBA(107, 114, 128, 1)
                                                LayoutMinHeight: =0
                                                LayoutMinWidth: =0
                                                Size: =11
                                                Text: ="Audit trail of decisions"
                                          - cmpApTimeline:
                                              Control: CanvasComponent
                                              ComponentName: cmpActivityTimeline
                                              Properties:
                                                AlignInContainer: =AlignInContainer.Stretch
                                                CardHeight: =96
                                                FillPortions: =1
                                                FilterOptions: |-
                                                  =Table({Value: "All Activities"})
                                                Height: =Parent.Height - 70
                                                HideHeader: =true
                                                IconMap: =nfApTimelineIcons
                                                IsLoading: =false
                                                Items: =nfApHistory
                                                LayoutMinHeight: =0
                                                LayoutMinWidth: =0
                                                OnExport: =false
                                                OnItemSelect: =false
                                                OnPrint: =false
                                                ShowScrollbar: =true
                                                SubDetailCardHeight: =160
                                                Theme: ="Light"
                                                ThemeConfig: =nfApTimelineTheme
                                                Width: =Parent.Width - 24
                        - cntBottomBarAp:
                            Control: GroupContainer@1.5.0
                            Variant: AutoLayout
                            Properties:
                              DropShadow: =DropShadow.None
                              Fill: =RGBA(255, 255, 255, 1)
                              FillPortions: =0
                              Height: =If(App.Width < 640, 58, 66)
                              LayoutAlignItems: =LayoutAlignItems.Center
                              LayoutDirection: =LayoutDirection.Vertical
                              LayoutMaxHeight: =If(App.Width < 640, 58, 66)
                              LayoutMinHeight: =If(App.Width < 640, 58, 66)
                              PaddingBottom: =4
                              PaddingTop: =4
                              Visible: =App.Width < 1024
                            Children:
                              - cmpApBottomNav:
                                  Control: CanvasComponent
                                  ComponentName: cmpBottomNavigation
                                  Properties:
                                    ActiveColor: =RGBA(37, 99, 235, 1)
                                    ActiveColorHex: ="2563EB"
                                    ActiveIndicator: ="underline"
                                    BadgeColor: =RGBA(220, 38, 38, 1)
                                    Fill: =RGBA(255, 255, 255, 1)
                                    Height: =Parent.Height - 8
                                    InactiveColorHex: ="9CA3AF"
                                    Items: |-
                                      =Table(
                                          {Index: 1, Icon: "dashboard", Label: "Dashboard", Badge: 0},
                                          {Index: 2, Icon: "analytics", Label: "Items",     Badge: 0},
                                          {Index: 3, Icon: "folder",      Label: "Approvals", Badge: nfApPendingCount},
                                          {Index: 4, Icon: "user",      Label: "Account",   Badge: 0}
                                      )
                                    OnSelect: |-
                                      =Set(gblApActiveTab, cmpApBottomNav.SelectedItemIndex);
                                      Switch(
                                          cmpApBottomNav.SelectedItemIndex,
                                          1, Notify("Navigate to Dashboard", NotificationType.Information),
                                          2, Notify("Navigate to Items", NotificationType.Information),
                                          3, false,
                                          4, Notify("Navigate to Account", NotificationType.Information)
                                      )
                                    SelectedIndex: =gblApActiveTab
                                    ShowLabels: ="always"
                                    Theme: ="Light"
                                    Width: =Parent.Width
      - cntLeftNavHostAp:
          Control: GroupContainer@1.5.0
          Variant: ManualLayout
          Properties:
            DropShadow: =DropShadow.None
            Fill: =RGBA(13, 17, 23, 1)
            Height: =Parent.Height
            Visible: =App.Width >= 1024
            Width: =If(_cmpNavIsExpanded, 224, 52)
          Children:
            - cmpApSidebar:
                Control: CanvasComponent
                ComponentName: cmpSidebar
                Properties:
                  AccentColor: =RGBA(37, 99, 235, 1)
                  AppLogo: =Blank()
                  AppName: ="Finance"
                  AppNameAccent: ="Ops"
                  Expanded: =true
                  Height: =App.Height
                  Icons: |-
                    =Table(
                        {Name: "Dashboard", SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='3' width='7' height='7' rx='1'/><rect x='14' y='3' width='7' height='7' rx='1'/><rect x='3' y='14' width='7' height='7' rx='1'/><rect x='14' y='14' width='7' height='7' rx='1'/></svg>"},
                        {Name: "List",      SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='3' y1='6' x2='21' y2='6'/><line x1='3' y1='12' x2='21' y2='12'/><line x1='3' y1='18' x2='21' y2='18'/></svg>"},
                        {Name: "Check",     SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M22 11.08V12a10 10 0 1 1-5.93-9.14'/><polyline points='22 4 12 14.01 9 11.01'/></svg>"},
                        {Name: "Receipt",   SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 2v20l3-2 3 2 3-2 3 2 3-2V2l-3 2-3-2-3 2-3-2z'/><line x1='8' y1='9' x2='16' y2='9'/><line x1='8' y1='14' x2='14' y2='14'/></svg>"},
                        {Name: "Chart",     SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='18' y1='20' x2='18' y2='10'/><line x1='12' y1='20' x2='12' y2='4'/><line x1='6' y1='20' x2='6' y2='14'/></svg>"},
                        {Name: "Settings",  SVG: "<svg viewBox='0 0 24 24' width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='3'/><path d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z'/></svg>"}
                    )
                  Items: |-
                    =Table(
                        {ID: 100, Title: "OVERVIEW",  Icon: "",          Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: true,  ParentID: -1},
                        {ID: 1,   Title: "Dashboard", Icon: "Dashboard", Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: false, ParentID: -1},
                        {ID: 2,   Title: "Requests",  Icon: "List",      Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: false, ParentID: -1},
                        {ID: 101, Title: "REVIEW",    Icon: "",          Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: true,  ParentID: -1},
                        {ID: 3,   Title: "Approvals", Icon: "Check",     Letter: "", Badge: nfApPendingCount, Visible: true, BadgeColor: RGBA(220, 38, 38, 1), BadgeDot: false, IsSection: false, ParentID: -1},
                        {ID: 4,   Title: "Expenses",  Icon: "Receipt",   Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: false, ParentID: -1},
                        {ID: 102, Title: "REPORTS",   Icon: "",          Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: true,  ParentID: -1},
                        {ID: 5,   Title: "Spend",     Icon: "Chart",     Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: false, ParentID: -1},
                        {ID: 6,   Title: "Settings",  Icon: "Settings",  Letter: "", Badge: 0,                Visible: true, BadgeColor: RGBA(0, 0, 0, 0),     BadgeDot: false, IsSection: false, ParentID: -1}
                    )
                  OnFooterSettings: =Notify("Settings coming soon", NotificationType.Information)
                  OnHelp: =Notify("Help coming soon", NotificationType.Information)
                  OnNavSelect: |-
                    =Switch(
                        cmpApSidebar.SelectedID,
                        1, Notify("Navigate to Dashboard", NotificationType.Information),
                        2, Notify("Requests coming soon", NotificationType.Information),
                        3, false,
                        4, Notify("Expenses coming soon", NotificationType.Information),
                        5, Notify("Spend reports coming soon", NotificationType.Information),
                        6, Notify("Settings coming soon", NotificationType.Information)
                    )
                  OnThemeToggle: =false
                  OnToggle: =false
                  ShowFooterMenu: =true
                  ShowHeader: =true
                  ShowSearch: =false
                  ShowToggle: =true
                  ShowUser: =true
                  Theme: ="Dark"
                  Width: =If(_cmpNavIsExpanded, 224, 52)
      - htmApSheetScrim:
          Control: HtmlViewer@2.1.0
          Properties:
            Font: =Font.'Segoe UI'
            Height: =Parent.Height
            HtmlText: ="<div style='display:block;width:" & Self.Width & "px;height:" & Self.Height - 1 & "px;background:rgba(15,23,42,0.42);backdrop-filter:blur(3px)'></div>"
            OnSelect: |-
              =UpdateContext({locApSheetOpen: false})
            PaddingBottom: =0
            PaddingLeft: =0
            PaddingRight: =0
            PaddingTop: =0
            Visible: =locApSheetOpen && App.Width < 1024
            Width: =Parent.Width
      - conApSheet:
          Control: GroupContainer@1.5.0
          Variant: AutoLayout
          Properties:
            DropShadow: =DropShadow.Bold
            Fill: =RGBA(255, 255, 255, 1)
            Height: =Min(Parent.Height * 0.86, 620)
            LayoutDirection: =LayoutDirection.Vertical
            RadiusTopLeft: =18
            RadiusTopRight: =18
            Visible: =locApSheetOpen && App.Width < 1024
            Width: =Parent.Width
            Y: =Parent.Height - Self.Height
          Children:
            - conApSheetHandleRow:
                Control: GroupContainer@1.5.0
                Variant: AutoLayout
                Properties:
                  DropShadow: =DropShadow.None
                  FillPortions: =0
                  Height: =18
                  LayoutAlignItems: =LayoutAlignItems.Center
                  LayoutDirection: =LayoutDirection.Vertical
                  LayoutJustifyContent: =LayoutJustifyContent.Center
                  LayoutMinHeight: =0
                Children:
                  - shpApSheetHandle:
                      Control: Rectangle@2.3.0
                      Properties:
                        BorderStyle: =BorderStyle.None
                        Fill: =RGBA(209, 213, 219, 1)
                        Height: =4
                        LayoutMinHeight: =4
                        LayoutMinWidth: =38
                        Width: =38
            - conApSheetHead:
                Control: GroupContainer@1.5.0
                Variant: AutoLayout
                Properties:
                  DropShadow: =DropShadow.None
                  FillPortions: =0
                  Height: =44
                  LayoutAlignItems: =LayoutAlignItems.Center
                  LayoutDirection: =LayoutDirection.Horizontal
                  LayoutGap: =8
                  LayoutMinHeight: =0
                  PaddingLeft: =16
                  PaddingRight: =12
                Children:
                  - lblApSheetTitle:
                      Control: ModernText@1.0.0
                      Properties:
                        AutoHeight: =true
                        Color: =RGBA(17, 24, 39, 1)
                        FillPortions: =1
                        FontWeight: =FontWeight.Bold
                        LayoutMinHeight: =0
                        LayoutMinWidth: =0
                        Size: =14
                        Text: ="Activity"
                  - btnApSheetClose:
                      Control: Button@0.0.45
                      Properties:
                        Appearance: ='ButtonCanvas.Appearance'.Subtle
                        Height: =30
                        Icon: ="Dismiss"
                        LayoutMinHeight: =0
                        LayoutMinWidth: =0
                        OnSelect: |-
                          =UpdateContext({locApSheetOpen: false})
                        Text: =""
                        Width: =32
            - shpApSheetDivider:
                Control: Rectangle@2.3.0
                Properties:
                  AlignInContainer: =AlignInContainer.Stretch
                  BorderStyle: =BorderStyle.None
                  Fill: =RGBA(229, 231, 235, 1)
                  Height: =1
                  LayoutMinHeight: =1
            - cmpApSheetTimeline:
                Control: CanvasComponent
                ComponentName: cmpActivityTimeline
                Properties:
                  AlignInContainer: =AlignInContainer.Stretch
                  CardHeight: =96
                  FillPortions: =1
                  FilterOptions: |-
                    =Table({Value: "All Activities"})
                  Height: =Parent.Height - 70
                  HideHeader: =true
                  IconMap: =nfApTimelineIcons
                  IsLoading: =false
                  Items: =nfApHistory
                  LayoutMinHeight: =0
                  LayoutMinWidth: =0
                  OnExport: =false
                  OnItemSelect: =false
                  OnPrint: =false
                  ShowScrollbar: =true
                  SubDetailCardHeight: =160
                  Theme: ="Light"
                  ThemeConfig: =nfApTimelineTheme
                  Width: =Parent.Width - 24
      - cmpApActionDialog:
          Control: CanvasComponent
          ComponentName: cmpEnhancedDialog
          Properties:
            BorderRadius: =12
            Buttons: |-
              =Table(
                  {Label: "Cancel", ButtonType: "Secondary", Action: "Cancel", Visible: true},
                  {
                      Label: If(gblApAction = "Reject", "Reject", "Send back"),
                      ButtonType: "Primary",
                      Action: "Commit",
                      Visible: true
                  }
              )
            DialogHeight: =0
            DialogType: ="Form"
            DialogWidth: =520
            HeaderText: |-
              =If(gblApAction = "Reject", "Reject ", "Send back ") &
              Coalesce(nfApActionRecord.ReqID, "request")
            Height: =Parent.Height
            IconName: =If(gblApAction = "Reject", "Warning", "Info")
            IsTextInputRequired: =true
            MessageText: |-
              =nfApActionRecord.Title & " · " &
              Text(nfApActionRecord.Amount, "[$-en-US]$#,##0") & " · requested by " &
              nfApActionRecord.Requester & ". " &
              If(
                  gblApAction = "Reject",
                  "This closes the request. The reason below is written to the audit trail.",
                  "This returns the request to the requester for revision. Explain what needs to change."
              )
            OnButtonSelect: |-
              =If(
                  cmpApActionDialog.SelectedButton.Action = "Commit",
                  // SWAP POINT: replace both statements with a flow call that owns the
                  // transition, e.g. flowDecide.Run(gblApActionID, nfApActionTarget, cmpApActionDialog.InputText)
                  Collect(colApHistory,
                      {
                          EventTitle: nfApActionTarget,
                          EventDescription: nfApActionRecord.ReqID & " · " & Text(nfApActionRecord.Amount, "[$-en-US]$#,##0"),
                          Author: "You",
                          EventOn: Now(),
                          Category: nfApActionTarget,
                          HasSubDetail: true,
                          SubTo: nfApActionRecord.Requester,
                          SubCC: "",
                          SubPriority: "Normal",
                          SubMessage: cmpApActionDialog.InputText
                      }
                  );
                  UpdateIf(
                      colApRequests,
                      ReqID = gblApActionID,
                      {
                          Status: nfApActionTarget,
                          DecidedBy: "You",
                          DecidedOn: Now(),
                          DecisionNote: cmpApActionDialog.InputText,
                          Selected: false
                      }
                  )
              );
              Set(gblApActionID, "");
              Set(gblApAction, "")
            OnCloseSelect: |-
              =Set(gblApActionID, "");
              Set(gblApAction, "")
            OverlayBlurColor: ="RGBA(15, 23, 42, 0.45)"
            PlaceholderText: =If(gblApAction = "Reject", "Reason for rejection", "What needs to change")
            ShowCloseIcon: =true
            Theme: ="Light"
            Visible: =!IsBlank(gblApActionID)
            Width: =Parent.Width

How It Works

1

Statuses are data, not code

Every status decision routes through colApStatus. IsOpen marks the one status the approver still acts on, and nfApOpenKey reads it. Adding a fifth outcome is a new data row — the queue, tabs, and counts all follow.

nfApOpenKey = LookUp(colApStatus, IsOpen, StatusKey)
2

Tabs are a projection of the status config

nfApTabOptions maps colApStatus (in Order) to Segmented Control options, with the live count carried inside each label since the component has no Badge column. Selecting a tab sets gblApFilter, which nfApFiltered reads.

nfApTabOptions = ForAll(Sort(colApStatus, Order), { Value: StatusKey, Label: Label & " (" & CountRows(Filter(colApRequests, Status = StatusKey)) & ")" })
3

The dialog looks its record back up by ID

cmpEnhancedDialog lives outside the gallery, so ThisItem isn't in scope. gblApActionID holds the request's ReqID and nfApActionRecord rehydrates it. nfApActionTarget maps the action to the status it commits to.

nfApActionRecord = LookUp(colApRequests, ReqID = gblApActionID) nfApActionTarget = If(gblApAction = "Reject", "Rejected", "Returned")
4

History stores a real datetime, then derives the label

colApHistory keeps an EventOn datetime (never a display string) so entries stay sortable as Collect() appends them. nfApHistory derives DisplayDateTime so seeded and freshly-written rows read identically instead of mixing “2 days ago” with a timestamp.

DisplayDateTime: Switch(true, _m < 1, "just now", _m < 60, _m & " min ago", …)
5

The value KPI guards the aggregate

Sum() over an empty table returns blank, so nfApPendingValue wraps it in If(IsEmpty(_p), 0, …). Sum isn't delegable — fine for the seeded collection this ships as; precompute with Power Automate against a real list.

nfApPendingValue = If(IsEmpty(_p), 0, Sum(_p, Amount))

Customization

Connect your data

Replace the ClearCollect(colApRequests, Table(…)) seed in the screen's OnVisible with your SharePoint list or Dataverse table. Keep the Status, Amount, SubmittedOn, and DecidedOn fields the formulas rely on.

Add an approval outcome

Add a row to colApStatus with a StatusKey, Label, Order, and IsOpen flag. A new tab, count, and filter appear automatically — no formula changes needed.

Change the KPIs

The three KPI cards read nfApPendingCount, nfApPendingValue, and nfApApprovedThisMonth. Edit those named formulas to track whatever metric matters to your process.

Require a reason per action

The reject / return path sets IsTextInputRequired on cmpEnhancedDialog so the approver can't commit without a note. Toggle it per action if approvals should be one-tap but rejections must be explained.

Wire real decision history

On commit, Collect() a row into colApHistory with an EventOn of Now(). nfApHistory + nfApTimelineIcons render it in the Activity Timeline — no display formatting to maintain.

Get new components and templates when they drop

One email when something new ships. Unsubscribe anytime.

Community

Use the toolbar to format · or type markdown directly