Skip to content

kimtth/ppf-powerapp-ingest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Power App Ingest

PowerApp UI Component Tree Generator. Generate visual component trees from PowerApp .msapp or .zip containing .msapp files with UI hierarchy, PowerFx expressions, and template metadata.

Why This Tool?

When asking Copilot or coding tools for Power Fx expressions, they often return hallucinations or verbose answers without understanding the UI hierarchy structure. This tool extracts UI hierarchy and associated Power Fx from PowerApp msapp or zip files to provide proper context to LLMs.

Key Benefits:

  • Provides accurate UI component hierarchy for AI context
  • Extracts only relevant Power Fx expressions (filters noise)
  • Enables better AI-assisted PowerApp development
  • Eliminates hallucinations by providing real app structure

Build Windows executable

# Install the dependencies and run the script.
uv sync
# Build Windows executable (pacingest.exe)
pyinstaller --onefile --name pacingest powerapp_tree_generator.py

Usage

# Template
pacingest "<INPUT_ZIP_OR_MSAPP_PATH>" --template --powerfx --metadata --output "<OUTPUT_FILE>"

# Basic tree
pacingest sample.msapp

# With component type metadata
pacingest sample.msapp --metadata

# With template names
pacingest sample.msapp --template

# With PowerFx expressions (complex data handling Power Fx only)
pacingest sample.msapp --powerfx

# All options combined & Save to file
pacingest sample.msapp --metadata --template --powerfx --output tree.txt

# Works with zip files containing msapp files
pacingest archive.zip --metadata

Command-Line Options

Option Description
path Path to .msapp or .zip file (required)
--metadata Show component types and variants
--template Show template names
--powerfx Show complex PowerFx expressions (filters SVG/theme data)
--output Save output to file

Output Example

The sample.zip app is sourced from the following URL.

Rijksmuseum Sample App
    β”œβ”€β”€ App [type:appinfo]
    β”‚   └── Host [type:hostControl]
    β”œβ”€β”€ Advanced Search [type:screen]
    β”‚   β”œβ”€β”€ Image2_1 [type:image]
    β”‚   β”œβ”€β”€ ico_Home [type:icon]
    β”‚   β”œβ”€β”€ lbl_AdvSearch [type:label]
    β”‚   β”œβ”€β”€ SearchBox1_1 [type:cat_PowerCAT.SearchBox]
    β”‚   β”œβ”€β”€ lbl_PrincipalMaker [type:label]
    β”‚   β”œβ”€β”€ txt_PrincipalMaker [type:text]
    β”‚   β”œβ”€β”€ FluentDetailsList1_1 [type:cat_PowerCAT.FluentDetailsList]
    β”‚   β”‚   β”œβ”€β”€ objectNumber1_1 [type:pcfDataField]
    β”‚   β”‚   β”œβ”€β”€ longTitle1_1 [type:pcfDataField]
    β”‚   β”‚   β”œβ”€β”€ headerImage1_1 [type:pcfDataField]
    β”‚   β”‚   β”œβ”€β”€ Link1_1 [type:pcfDataField]
    β”‚   β”‚   └── WebURL1_1 [type:pcfDataField]
    β”‚   β”œβ”€β”€ lbl_Language [type:label]
    β”‚   β”œβ”€β”€ drp_Language [type:dropdown]
    β”‚   β”œβ”€β”€ lbl_Century [type:label]
    β”‚   β”œβ”€β”€ txt_Century [type:text]
    β”‚   β”œβ”€β”€ lbl_ResultsperPage [type:label]
    β”‚   β”œβ”€β”€ txt_ResultperPage [type:text]
    β”‚   β”œβ”€β”€ btn_SearchCollectionFlow [type:button]
    β”‚   └── grp_AdvSearchItems [type:group]
    └── Home [type:screen]
        β”œβ”€β”€ Image2 [type:image]
        β”œβ”€β”€ Pivot1 [type:cat_PowerCAT.Pivot]
        β”œβ”€β”€ SearchBox1 [type:cat_PowerCAT.SearchBox]
        └── FluentDetailsList1 [type:cat_PowerCAT.FluentDetailsList]
            β”œβ”€β”€ objectNumber1 [type:pcfDataField]
            β”œβ”€β”€ principalOrFirstMaker1 [type:pcfDataField]
            β”œβ”€β”€ longTitle1 [type:pcfDataField]
            β”œβ”€β”€ headerImage1 [type:pcfDataField]
            β”œβ”€β”€ Link1 [type:pcfDataField]
            └── WebURL1 [type:pcfDataField]

With PowerFx expressions (--powerfx flag)

Expand
Rijksmuseum Sample App
    β”œβ”€β”€ App [type:appinfo]
    β”‚   fx[OnStart]: Set(
    β”‚                    AppTheme,
    β”‚                    {
    β”‚                        palette: {
    β”‚                            themePrimary: "#FFFFFF",
    β”‚                            themeLighterAlt: "#767676",
    β”‚                            themeLighter: "#a6a6a6",
    β”‚                            themeLight: "#c8c8c8",
    β”‚                            themeTertiary: "#d0d0d0",
    β”‚                            themeSecondary: "#dadada",
    β”‚                            themeDarkAlt: "#eaeaea",
    β”‚                            themeDark: "#f4f4f4",
    β”‚                            themeDarker: "#f8f8f8",
    β”‚                            neutralLighterAlt: "#0b0b0b",
    β”‚                            neutralLighter: "#151515",
    β”‚                            neutralLight: "#252525",
    β”‚                            neutralQuaternaryAlt: "#2f2f2f",
    β”‚                            neutralQuaternary: "#373737",
    β”‚                            neutralTertiaryAlt: "#595959",
    β”‚                            neutralTertiary: "#4d3b1d",
    β”‚                            neutralSecondary: "#99763a",
    β”‚                            neutralPrimaryAlt: "#e0ad55",
    β”‚                            neutralPrimary: "#ffc561",
    β”‚                            neutralDark: "#ffd387",
    β”‚                            black: "#ffdfa6",
    β”‚                            white: "#000000"
    β”‚                        }
    β”‚                    }
    β”‚                );
    β”‚                Set(
    β”‚                    AppThemeJson,
    β”‚                    JSON(
    β”‚                        AppTheme,
    β”‚                        JSONFormat.IndentFour
    β”‚                    )
    β”‚                );
    β”‚                
    β”‚                ClearCollect(
    β”‚                    searchCollectionFirst100,
    β”‚                    'Rijksmuseum(IndependentPublisher)'.GetCollection(
    β”‚                        "nl",
    β”‚                        {
    β”‚                            p: 1,
    β”‚                            ps: 100
    β”‚                        }
    β”‚                    )
    β”‚                );
    β”‚                ClearCollect(
    β”‚                    searchCollectionResultTop100,
    β”‚                    AddColumns(
    β”‚                    Ungroup(
    β”‚                        searchCollectionFirst100.artObjects,
    β”‚                        "artObjects"
    β”‚                    ),
    β”‚                    "WebURL",webImage.url,"Link",links.web)
    β”‚                );
    β”‚                
    β”‚   └── Host [type:hostControl]
    β”œβ”€β”€ Advanced Search [type:screen]
    β”‚   β”œβ”€β”€ Image2_1 [type:image]
    β”‚   β”œβ”€β”€ ico_Home [type:icon]
    β”‚   β”œβ”€β”€ lbl_AdvSearch [type:label]
    β”‚   β”œβ”€β”€ SearchBox1_1 [type:cat_PowerCAT.SearchBox]
    β”‚   β”œβ”€β”€ lbl_PrincipalMaker [type:label]
    β”‚   β”œβ”€β”€ txt_PrincipalMaker [type:text]
    β”‚   β”œβ”€β”€ FluentDetailsList1_1 [type:cat_PowerCAT.FluentDetailsList]
    β”‚   β”‚   fx[columns_Items]: Table(
    β”‚   β”‚                          {
    β”‚   β”‚                              ColDisplayName: "✍️ Principal/First Maker",
    β”‚   β”‚                              ColName: "principalOrFirstMaker",
    β”‚   β”‚                              ColResizable: true,
    β”‚   β”‚                              ColWidth: 200,
    β”‚   β”‚                              ColRowHeader: true
    β”‚   β”‚                          },
    β”‚   β”‚                          {
    β”‚   β”‚                              ColDisplayName: "🏒 Object Number",
    β”‚   β”‚                              ColName: "objectNumber",
    β”‚   β”‚                              ColResizable: true,
    β”‚   β”‚                              ColWidth: 150,
    β”‚   β”‚                              ColRowHeader: true
    β”‚   β”‚                          },
    β”‚   β”‚                          {
    β”‚   β”‚                              ColDisplayName: "πŸ“° Title",
    β”‚   β”‚                              ColName: "longTitle",
    β”‚   β”‚                              ColBold: true,
    β”‚   β”‚                              ColWidth: 300,
    β”‚   β”‚                              ColRowHeader: true,
    β”‚   β”‚                              ColResizable: true,
    β”‚   β”‚                              ColMultiLine: true
    β”‚   β”‚                          },
    β”‚   β”‚                          {
    β”‚   β”‚                              ColDisplayName: "πŸ–ΌοΈ Image",
    β”‚   β”‚                              ColName: "WebURL",
    β”‚   β”‚                              ColBold: true,
    β”‚   β”‚                              ColWidth: 100,
    β”‚   β”‚                              ColRowHeader: true,
    β”‚   β”‚                              ColResizable: true,
    β”‚   β”‚                              ColCellType: "image",
    β”‚   β”‚                              ColImageWidth: 60,
    β”‚   β”‚                              ColImagePadding: 6
    β”‚   β”‚                          },
    β”‚   β”‚                          {
    β”‚   β”‚                              ColDisplayName: "πŸ”—Link",
    β”‚   β”‚                              ColName: "Link",
    β”‚   β”‚                              ColBold: true,
    β”‚   β”‚                              ColWidth: 400,
    β”‚   β”‚                              ColRowHeader: true,
    β”‚   β”‚                              ColResizable: true,
    β”‚   β”‚                              ColCellType: "link",
    β”‚   β”‚                              ColMultiLine: true
    β”‚   β”‚                          }
    β”‚   β”‚                      )
    β”‚   β”‚   fx[Items]: If(
    β”‚   β”‚                  Len(SearchBox1_1.SearchText) >= 3,
    β”‚   β”‚                  SortByColumns(
    β”‚   β”‚                      Search(
    β”‚   β”‚                          colAdvSearchTable,
    β”‚   β”‚                          SearchBox1_1.SearchText,
    β”‚   β”‚                          "principalOrFirstMaker",
    β”‚   β”‚                          "longTitle",
    β”‚   β”‚                          "objectNumber"
    β”‚   β”‚                      ),
    β”‚   β”‚                      ctxSortCol,
    β”‚   β”‚                      If(
    β”‚   β”‚                          ctxSortAsc,
    β”‚   β”‚                          SortOrder.Ascending,
    β”‚   β”‚                          SortOrder.Descending
    β”‚   β”‚                      )
    β”‚   β”‚                  ),
    β”‚   β”‚                  SortByColumns(
    β”‚   β”‚                      colAdvSearchTable,
    β”‚   β”‚                      ctxSortCol,
    β”‚   β”‚                      If(
    β”‚   β”‚                          ctxSortAsc,
    β”‚   β”‚                          SortOrder.Ascending,
    β”‚   β”‚                          SortOrder.Descending
    β”‚   β”‚                      )
    β”‚   β”‚                  )
    β”‚   β”‚              )
    β”‚   β”‚   fx[OnChange]: If(Self.EventName="Sort", 
    β”‚   β”‚                 UpdateContext({
    β”‚   β”‚                                 ctxSortCol:Self.SortEventColumn,
    β”‚   β”‚                                 ctxSortAsc:If(Self.SortEventDirection='PowerCAT.FluentDetailsList.SortEventDirection'.Ascending,true,false)
    β”‚   β”‚                  })
    β”‚   β”‚                 );
    β”‚   β”‚                 
    β”‚   β”‚                 If(Self.EventName="CellAction",    Launch(Self.Selected.Link))
    β”‚   β”‚   β”œβ”€β”€ objectNumber1_1 [type:pcfDataField]
    β”‚   β”‚   β”œβ”€β”€ longTitle1_1 [type:pcfDataField]
    β”‚   β”‚   β”œβ”€β”€ headerImage1_1 [type:pcfDataField]
    β”‚   β”‚   β”œβ”€β”€ Link1_1 [type:pcfDataField]
    β”‚   β”‚   └── WebURL1_1 [type:pcfDataField]
    β”‚   β”œβ”€β”€ lbl_Language [type:label]
    β”‚   β”œβ”€β”€ drp_Language [type:dropdown]
    β”‚   β”œβ”€β”€ lbl_Century [type:label]
    β”‚   β”œβ”€β”€ txt_Century [type:text]
    β”‚   β”œβ”€β”€ lbl_ResultsperPage [type:label]
    β”‚   β”œβ”€β”€ txt_ResultperPage [type:text]
    β”‚   β”œβ”€β”€ btn_SearchCollectionFlow [type:button]
    β”‚   β”‚   fx[OnSelect]: ClearCollect(
    β”‚   β”‚                     colAdvSearch,
    β”‚   β”‚                     RijksmuseumSearchCollection.Run(
    β”‚   β”‚                         drp_Language.Selected.Value,
    β”‚   β”‚                         txt_PrincipalMaker.Text,
    β”‚   β”‚                         Value(txt_ResultperPage.Text),
    β”‚   β”‚                         Value(txt_Century.Text)
    β”‚   β”‚                     )
    β”‚   β”‚                 );
    β”‚   β”‚                 ClearCollect(
    β”‚   β”‚                     colAdvSearchTable,
    β”‚   β”‚                     AddColumns(colAdvSearch,
    β”‚   β”‚                     "WebURL",webImage.url,"Link",links.web)
    β”‚   β”‚                 )
    β”‚   └── grp_AdvSearchItems [type:group]
    └── Home [type:screen]
        β”œβ”€β”€ Image2 [type:image]
        β”œβ”€β”€ Pivot1 [type:cat_PowerCAT.Pivot]
        β”‚   fx[Items]: Table(
        β”‚                  {
        β”‚                      ItemKey: "Home",
        β”‚                      ItemDisplayName: "Home",
        β”‚                      ItemIconName: "Home"
        β”‚                  },
        β”‚                  {
        β”‚                      ItemKey : "SearchCollection",
        β”‚                      ItemDisplayName: "Search Collection",
        β”‚                      ItemIconName: "SearchData"
        β”‚                  }
        β”‚              )
        β”‚   fx[OnSelect]: Switch(
        β”‚                     Self.SelectedKey,
        β”‚                     "Home",
        β”‚                     searchCollectionResultTop100,
        β”‚                     "SearchCollection",
        β”‚                     Navigate('Advanced Search',ScreenTransition.Cover)
        β”‚                     )
        β”œβ”€β”€ SearchBox1 [type:cat_PowerCAT.SearchBox]
        └── FluentDetailsList1 [type:cat_PowerCAT.FluentDetailsList]
            fx[columns_Items]: Table(
                                   {
                                       ColDisplayName: "✍️ Principal/First Maker",
                                       ColName: "principalOrFirstMaker",
                                       ColResizable: true,
                                       ColWidth: 200,
                                       ColRowHeader: true
                                   },
                                   {
                                       ColDisplayName: "🏒 Object Number",
                                       ColName: "objectNumber",
                                       ColResizable: true,
                                       ColWidth: 150,
                                       ColRowHeader: true
                                   },
                                   {
                                       ColDisplayName: "πŸ“° Title",
                                       ColName: "longTitle",
                                       ColBold: true,
                                       ColWidth: 300,
                                       ColRowHeader: true,
                                       ColResizable: true,
                                       ColMultiLine: true
                                   },
                                   {
                                       ColDisplayName: "πŸ–ΌοΈ Image",
                                       ColName: "WebURL",
                                       ColBold: true,
                                       ColWidth: 100,
                                       ColRowHeader: true,
                                       ColResizable: true,
                                       ColCellType: "image",
                                       ColImageWidth: 60,
                                       ColImagePadding: 6
                                   },
                                   {
                                       ColDisplayName: "πŸ”—Link",
                                       ColName: "Link",
                                       ColBold: true,
                                       ColWidth: 400,
                                       ColRowHeader: true,
                                       ColResizable: true,
                                       ColCellType: "link",
                                       ColMultiLine: true
                                   }
                               )
            fx[Items]: If(
                           Len(SearchBox1.SearchText) >= 3,
                           SortByColumns(
                               Search(
                                   searchCollectionResultTop100,
                                   SearchBox1.SearchText,
                                   "principalOrFirstMaker",
                                   "longTitle",
                                   "objectNumber"
                               ),
                               ctxSortCol,
                               If(
                                   ctxSortAsc,
                                   SortOrder.Ascending,
                                   SortOrder.Descending
                               )
                           ),
                           SortByColumns(
                               searchCollectionResultTop100,
                               ctxSortCol,
                               If(
                                   ctxSortAsc,
                                   SortOrder.Ascending,
                                   SortOrder.Descending
                               )
                           )
                       )
            fx[OnChange]: If(Self.EventName="Sort", 
                          UpdateContext({
                                          ctxSortCol:Self.SortEventColumn,
                                          ctxSortAsc:If(Self.SortEventDirection='PowerCAT.FluentDetailsList.SortEventDirection'.Ascending,true,false)
                           })
                          );
                          
                          If(Self.EventName="CellAction",    Launch(Self.Selected.Link))
            β”œβ”€β”€ objectNumber1 [type:pcfDataField]
            β”œβ”€β”€ principalOrFirstMaker1 [type:pcfDataField]
            β”œβ”€β”€ longTitle1 [type:pcfDataField]
            β”œβ”€β”€ headerImage1 [type:pcfDataField]
            β”œβ”€β”€ Link1 [type:pcfDataField]
            └── WebURL1 [type:pcfDataField]

TODO: MCP Integration

Future enhancement plan using Model Context Protocol (MCP):

See Power Platform MCP Documentation for integration details.

Power Platform CLI Setup (for MCP integration)

# Install the CLI globally using the .NET tool install command:
dotnet tool install --global Microsoft.PowerApps.CLI.Tool

# Verify the installation
pac

# Check mcp installation location
pac copilot mcp

# Verify your authentication profiles
pac auth list
pac auth create
pac auth select
pac auth who

References

About

πŸ—‚οΈ A git-ingest–inspired tool that generates Power Apps context (UI hierarchies and Power Fx) for LLMs, reducing hallucinations

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages