Skip to content

AndrewElans/PowerPagesSPA

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 

Repository files navigation

Power Pages SPA

Sample project of a Microsoft Power Pages Single Page Application with no "low code no code" principle. Provisioned with Vite and optional Node.js hosted as Azure Web App. Suitable for corporate environment with sensitive business data.

Features

  • Fully controlled dependencies in Power Pages
  • Sign-in with multiple accounts / switch accounts made easy without signout
  • Browser-based Microsoft Authentication Library for JavaScript authenticating with:
    • Azure AD
    • Dataverse (db behind Power Pages)
    • Azure Storage
    • Azure Cosmos DB
  • Role-based access control to resources and content
  • Lightweight
  • Custom logger
  • Multi-layered security on various levels
  • Techstack is limited to Azure SaaS cloud-based tools only
  • Pulling data from API endpoints with Flows or custom Node.js Web App
  • Syncing data with Dataflows
  • Optional Domain-Driven Design with Node.js Web App
    • Simple setup
    • Node.js as a proxy-server
    • Isolate business logic from system code

References

Sample project description

Supplier management portal to provide a buyer/procurement proffesional with information on suppliers organization is dealing with. The portal will keep internal stakeholders updated with current supplier status including challenges, delays and quality issues supplier is experiencing in projects or other engagements, prices and lead times actual vs committed, legal issues, evaluation of suppliers and more. The aim of the portal is to make buyer's work easier and more efficient, improve bargaining power in negotiations with suppliers and help take right business decisions during supplier selection to maintain "5 rights of procurement".

Steps

  1. Check if you have account in portal.azure.com. Use corporate Azure account or see how to make a new Azure developer subscription which can be created with any private email address / phone and credit card

My experience

  • I creat subscription with email [email protected], phone and credit card

  • When accessing portal.azure.com first time with this email, I see only a single user me with email ......#[email protected]

  • I adjust the email to [email protected]

  • This email I use further to access:

    • admin.cloud.microsoft - your main place to manage Azure account and services:
      • portal.azure.com
      • entra.microsoft.com
      • admin.powerplatform.microsoft.com
      • make.powerapps.com
      • make.powerpages.microsoft.com
  • First time I login to portal.azure.com with [email protected], the system will ask me to setup MFA authentication with a phone app Authenticator that you should have installed prior

  • You get the following licences on your account:

    • Microsoft Power Automate Free -> activated on your user
    • Microsoft Power Apps for Developer -> activated on your user
    • Power Pages vTrial for Makers -> not activated on your user
  1. Activate Power Pages vTrial for Makers licence

    This is preffered step over 3. Do it as explained here learn.microsoft.com/en-us/power-pages/getting-started/trial-signup.

    After filling out the form you get provisioned a power apps environment in admin.powerplatform.microsoft.com with name PowerPagesTrial-xxxxxx and Type Trial for 30 days.

    Difference between Trial and Developer environments

    Following step 2 you get Trial env which you can convert to Production that is a must to make you web site public, see here learn.microsoft.com/en-us/power-pages/security/site-visibility. Only in public mode you get your public routes to work for MSAL redirect, see Default pages with public access here dev.to/andrewelans/power-pages-spa-login-redirect-2g2n.

    In step 3 you get a Developer env that you cannot convert to Production and therefore make a Power Pages site public. Trying to convert it in make.powerpowerpages.microsoft.com, the system is sending this req under the hood:

    POST https://portalsitewide-nor.portal-infra.dynamics.com/api/v1/powerPortal/UpdateSiteVisibility?tenantId=GUID&portalId=GUID&siteVisibility=public

    with response 400:

    {
    	"Message": "Site visibility cannot be changed to public on developer environment.",
    	"ErrorCode": "D005",
    	"ErrorType": "User error"
    }

    After you have your env provisined, check this page dev.to/andrewelans/power-pages-spa-main-setup for adjusting authentication and redirectUri in App registration on portal.azure.com.

  2. Step 2 is preffered over this step. Provision a new powerapps environment (take a note on language), power pages portal and set it up as explained here dev.to/andrewelans/power-pages-spa-main-setup.

  3. Create 3 guest users

    Go to portal.azure.com.

    Users

    Add 3 new dummy users with User type Guest.

    • Bing Whatman
    • Gwenny Dinsell
    • Essa Stuckes

    When created, remember temporary passwords. When logging in with these users first time, you would need to update the password using the temporary one.

    Use permanent password DummyGuest1 for all users.

    Assing Power Apps licence to these user

    When a user does not have a licence, he will not appear as a user in Dataverse (Default Business unit and default Team). As a consequenc, trying to send a simple query like this https://250101.api.crm19.dynamics.com/api/data/v9.2/WhoAmI will return a 403 Forbidden error:

    {
    	"error": {
    		"code": "0x80072560",
    		"message": "The user is not a member of the organization."
    	}
    }

    Go to admin.microsoft.com -> Home -> find that these new users in Licences column has Unlicensed -> click on each user's ... -> assing Microsoft Power Apps for Developer. Go to admin.powerplatform.microsoft.com -> your env -> Settings -> Users -> click Add user -> and add new users one by one.

    You can also do this in bulk with Power Automate as explained in this blog matthewdevaney.com/force-sync-users-from-entra-security-group-to-dataverse-team.

    Re MFA

    Type Guest will have limited permissions in portal.azure.com and will not be required for MFA-authentication on power pages. However, Guests will still be requested to authenticate with MFA if they try to access:

    • Azure portal
    • Entra admin center
    • Intune admin center
    • M365 Admin center

    More on MFA:

    Users -> User settings

    Set most restrictive policy on users including guests.

    • Guest user access -> Activate Guest user access is restricted to properties and memberships of their own directory objects (most restrictive)
    • Restrict access to Microsoft Entra admin center ON
    • Show keep user signed in OFF
    • Allow users to connect their work or school account with LinkedIn No
    • External collaboration settings -> Guest invite restrictions -> No one in the organization can invite guest users including admins (most restrictive) ON
  4. Organization of the supplier management portal

    Access and content is provided based on the following grouping:

    Type Accessible Pages/Routes/Functionality Security Group Dataverse Team Users
    System Administrator Home
    Find Supplier
    Frame Agreements Write
    Admin
    SG-SYSTEM-ADMIN admin Andrew Elans
    Procurement users Home
    Find Supplier
    Frame Agreements Read
    SG-PROCUREMENT-ALL procall Bing Whatman
    Gwenny Dinsell
    Frame Agreement Managers Home
    Find Supplier
    Frame Agreements Write
    SG-FA-OWNER faowner Gwenny Dinsell
    All other tenant's users No access with request access form azure

    Each page has a corresponding snipet. Snippets are stored in a new Dataverse table with the following structure:

    Name az Val Admin az Val ProcAll az Val FAOwner az Val Azure az Val Common
    nav json content json content json content json content json content

    Each az Val.. column has Column security profile set up.

    Structure of json content:

    {
    	"seq": 1,
    	"name": "az_valshared",
    	"snippets": [
    		{
    			"name": "_home",
    			"title": "Home",
    			"route": "/",
    			"hash": "",
    			"html": "<h1>Home</h1><script>console.log(\"hi from home page\")</script>"
    		}
    	],
    	"divStr": "<li class=\"nav-item\"><button class=\"nav-link handler nav-home\" data-snippet=\"_home\">Home</button></li>",
    	"navbarModule": {
    		"name": "dynamic-02-navbar",
    		"fns": ["snippetsFn", "activateNavBtnFn"]
    	}
    }

    To be continued...

  5. Create Security Groups

    In portal.azure.com -> Groups create corresponding groups and add members.

  6. Create a new solution in make.powerapps.com dev.to/andrewelans/power-pages-spa-components-part-1

  7. Do some changes to default Power Pages components as per this post dev.to/andrewelans/power-pages-spa-components-part-2 and this repo github.com/AndrewElans/PowerPagesSPA-PowerPagesSetup.

    Testing portal urls

    You should now have a working web site with the following behaviour when requesting urls in a new inkognito window (provide you have enabled Public mode):

    • Redirect to login.microsoftonline.com:

      • site-250101.powerappsportals.com
      • site-250101.powerappsportals.com/dynamic-assets
      • site-250101.powerappsportals.com/static-assets
      • site-250101.powerappsportals.com/signin
    • Render Page Not Found:

      • site-250101.powerappsportals.com/page-not-found
      • site-250101.powerappsportals.com/lkjjkdjfkj
    • Render corresponding content:

      • site-250101.powerappsportals.com/cat-pc.png
      • site-250101.powerappsportals.com/access-denied
      • site-250101.powerappsportals.com/_layout/tokenhtml -> blank page with single input on body

    Checking dependencies

    Log in to your portal with your user. You will see your email on document.body.dataset.emailpowerpages.

    Open Dev Tools -> Sources -> Page.

    On all these pages the sources will not have any of the default power pages dependencies:

    • site-250101.powerappsportals.com
    • site-250101.powerappsportals.com/dynamic-assets
    • site-250101.powerappsportals.com/static-assets
    • site-250101.powerappsportals.com/page-not-found

    Go to site-250101.powerappsportals.com/access-denied see all default dependencies loaded and compare to our simplest setup.

    Performance

    Dev Tools -> Network

    • site-250101.powerappsportals.com/access-denied (with default deps)

      • 39 requests
      • 1.3 MB transferred
      • 4.8 MB resources (we can deduct the cat image from here to be objective)
    • site-250101.powerappsportals.com (w/o default deps)

      • 1 requests
      • 1.3 kB transferred
      • 382 B resources

    Dev Tools -> Performance

    • site-250101.powerappsportals.com/access-denied (with default deps)

      • Scripting 501 ms
      • System 165 ms
      • Loading 18 ms
      • Rendering 14 ms
      • Painting 1 ms
    • site-250101.powerappsportals.com (w/o default deps)

      • System 19 ms
      • Rendering 7 ms
      • Scripting 2 ms

    And these are very simple pages!

    Difference between this setup and default Microsoft Power Pages SPA

    Microsoft now provides SPA functionality as explained here learn.microsoft.com/en-us/power-pages/configure/create-code-sites.

    Let's convert our site into the default SPA and see the difference. To do this we add to settings CodeSite/Enabled set to true, resync and compare functionality on the same urls in inkognito.

    • Redirect to login.microsoftonline.com:

      • site-250101.powerappsportals.com no changes
      • site-250101.powerappsportals.com/dynamic-assets no changes
      • site-250101.powerappsportals.com/static-assets no changes
      • site-250101.powerappsportals.com/signin no changes
    • Render Page Not Found:

      • site-250101.powerappsportals.com/page-not-found no changes
      • site-250101.powerappsportals.com/lkjjkdjfkj changes: all default dependences are loaded. This behaviour will have undesired implication on our routing.
    • Render corresponding content:

      • site-250101.powerappsportals.com/cat-pc.png no changes
      • site-250101.powerappsportals.com/access-denied no changes
      • site-250101.powerappsportals.com/_layout/tokenhtml no changes
  8. Add table az Snippet

    Go to make.powerapps.com -> your env -> Tables -> New table -> Table (advanced properties)

    • Display name az Snippet
    • Schema name az_Snippet
    • Primary column:
      • Display name az Name
      • Schema name az_Name

    Add new columns az Val Admin, az Val ProcAll, az Val FAOwner, az Val Azure, az Val Common with:

    • Data type Multiple lines of text
    • Maximum character count 10000
    • Enable column security ON (except for az Val Azure)
    • Adjust Schema name to format az_Val...

    Open Forms on this table -> select form Information (Main) -> Edit -> add Multiline text with component Edit This Monaco editor is used in Power Pages Management App for each of the created columns.

    Not complete description. I will show in a video

  9. Edit Power Pages Management app

    Go to make.powerapps.com -> Apps -> Power Pages Management -> Edit.

    Add aa Snippets

    Find and select Web Templates form on the left -> click on top Add page -> Dataverse table -> select aa Snippet -> Add

    Now we can add and edit snippets directly in the app.

    Add Teams

    Select aa Snippets form added just now -> click on top Add page -> Dataverse table -> find and select Team -> Add

    Click Save and publish on top right.

  10. Create user views

    We will make custom user views to be able to call userQuery with Web API:

    • Teams user a member of
    • Snippets user has access to

    To be able to test your views in a browser, in a new tab go to make.powerapps.com -> setings cog on top right -> Developer resources -> copy Web API endpoint https://250101.api.crm19.dynamics.com/api/data/v9.2 -> paste URL origin in a the url bar https://250101.api.crm19.dynamics.com to authenticate this endpoint.

    New view aa User Teams

    In Power Pages Management app -> select Teams on the left -> Edit columns -> remove Business Unit -> Apply -> click Edit filters -> click Delete all filters -> click Add related entity -> find and select Users -> select in a field User and operator Equals current user -> Apply -> Save as new view -> name aa User Teams -> Save -> Set as default view -> click Manage and share views -> click ... of view aa User Teams -> Share -> in Add user/team find and select azure (our default tenant's team) -> add Permissions Read -> click Share -> Close -> copy from the url bar and take viewid from ...&viewid=a49fb75b-bdbb-f011-bbd3-6045bdeaa0cd....

    Run this query in the browser https://250101.api.crm19.dynamics.com/api/data/v9.2/teams?userQuery=a49fb75b-bdbb-f011-bbd3-6045bdeaa0cd.

    Response:

    {
    	"@odata.context": "https://250101.api.crm19.dynamics.com/api/data/v9.2/$metadata#teams(name,teamid,teamtype,ownerid)",
    	"value": [
    		{
    			"@odata.etag": "W/\"2012344\"",
    			"ownerid": "ac077676-1fbb-f011-bbd3-6045bdeaa0cd",
    			"teamtype": 2,
    			"name": "admin",
    			"teamid": "ac077676-1fbb-f011-bbd3-6045bdeaa0cd"
    		},
    		{
    			"@odata.etag": "W/\"2011269\"",
    			"ownerid": "da4f12c4-c4b6-f011-bbd3-002248dc6fd6",
    			"teamtype": 0,
    			"name": "azure",
    			"teamid": "da4f12c4-c4b6-f011-bbd3-002248dc6fd6"
    		}
    	]
    }

    New view aa User Snippets

    In Power Pages Management app -> select aa Snippets on the left -> Edit columns -> remove Created On -> Add columns -> add all custom created aa Val.. columns -> Close -> Apply -> Save as new view -> name aa User Snippets -> Save -> Set as default view -> click Manage and share views -> click ... of view aa User Teams -> Share -> in Add user/team find and select azure (our default tenant's team) -> add Permissions Read -> click Share -> Close -> copy from the url bar and take viewid from ...&viewid=f810968d-c7bb-f011-bbd3-6045bdeaa0cd....

    Click New to add new record to the aa Snippets -> name nav -> Save and close.

    Run this query in the browser https://250101.api.crm19.dynamics.com/api/data/v9.2/aa_snippets?userQuery=f810968d-c7bb-f011-bbd3-6045bdeaa0cd.

    Response:

    {
    	"@odata.context": "https://250101.api.crm19.dynamics.com/api/data/v9.2/$metadata#aa_snippets(statecode,aa_snippetid,aa_name,aa_valadmin,aa_valazure,aa_valcommon,aa_valfaowner,aa_valprocall)",
    	"value": [
    		{
    			"@odata.etag": "W/\"2090370\"",
    			"aa_name": "nav",
    			"statecode": 0,
    			"aa_snippetid": "270797bc-c7bb-f011-bbd3-6045bdeaa0cd"
    		}
    	]
    }
  11. Setup Dataverse

    Go to admin.powerplatform.microsoft.com -> your env -> Settings

    Users + Permissions

    • Business units -> I have one with name org459277b5 -> open -> edit -> rename to azure

    • Teams

      • delete all default teams present there except the one named azure
      • create new teams with as defined in the step 5 table with
        • Team name as in column Dataverse Team
        • Team type Microsoft Entra ID Security Group
        • Group name as in column Security Group
        • Membership type Members and guests

  12. Add defaut logging.

  13. Add security groups and create snippets.

  14. Set up MSAL Browser and Vite coming...

  15. ...

  16. ...

  17. ...

  18. Provision mock json data

  19. Set up Azure Cosmos DB to work with the MSAL token

Content is in progress...

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published