Solestyles Boutique Digital Transformation - Part 2 - Designing Solestyles Canvas App: A Mobile-First Experience

Introduction

When you step onto the shop floor at Solestyles Boutique, the first thing you notice is the ease with which our team can now check stock, launch special orders and capture customer requests, all from the same tablet they once used to scan barcodes in fringe-signal car parks. This transformation stems from one pivotal component of the Power Platform solution; the Canvas App. In this second part of the Solestyles blog series, I’ll explore how I crafted a truly mobile-first experience, optimised for speed, simplicity and real-world unpredictability.

 

In the previous post, you saw how tedious paper invoices and chaotic spreadsheets hampered everyday operations and drove our small West Yorkshire boutique to seek a unified, low-code backbone. Now it’s time to talk about the frontline interface.

Why choose a Canvas App over other options?

What design decisions would allow our shop assistants juggling deliveries, pop-ups and in store customers to navigate thousands of SKUs without a single spin of the wheel?

Over the next few sections, I’ll trace the Canvas App’s evolution from its first rough wireframes through to a polished, delegable search screen. You’ll learn how I linked directly to Dataverse and SharePoint Online, organised data into collections for lightning-fast lookups, and engineered the navigation so that any required screen lies just one tap away. Along the way, I’ll share the formulas and patterns (anonymised); like multi-field delegable filtering and offline sync queues that turned a simple gallery into a robust, resilient tool, capable of handling everything from a rogue power cut to a deluge of weekend footfall.

 

Whether you’re already designing your own Canvas App or simply curious about how low-code can revolutionise the customer facing edge of your business, this journey through Solestyles tablet interface should spark ideas and give you practical technical ideas to borrow. So grab your iPad, find a quiet corner of your boutique and let’s dive into the next section, where I’ll set up those crucial data connections and lay the foundations for every screen to come.

Setting Up Your Solution & App

Before a single control goes on canvas, it’s vital to establish a robust, solution aware foundation. By creating a proper solution and app record and by embedding environment variables and connection references; this ensures that your Canvas App is portable across environments, secure by design and easy to maintain.

Creating the Solution
  1. Open Power Apps Maker Portal – Go to https://make.powerapps.com and sign in.
  2. Navigate to Solutions – In the left-hand navigation pane, click Solutions.
  3. New Solution – At the top of the Solutions list, click the New solution button.
  4. Define Solution Properties:
    • Display Name: Solestyles Boutique
    • Name: solestyles_boutique
    • Publisher: {{YourPublisherPrefix}} – You can create a new one if one does not exist – don’t ever use the default publisher!
    • Version: 1.0.0.0
  5. Save – This creates an empty solution container for all your components, apps, flows, variables and more.

 

By packaging everything in one solution, deployments become a matter of exporting and importing a single ZIP file, rather than reconnecting each component manually.

Adding the Canvas App Record
  1. Select Your Solution – From the Solutions list, click the row for Solestyles Boutique to open its overview.
  2. Create a New Canvas App – In the command bar under the solution name, click New > App > Canvas app.
  3. Configure the App – Name: Solestyles Boutique App
    • Format: Tablet (16:9)
  4. Create – Power Apps Studio launches in a new tab with your solution-bound Canvas App.

 

Because the app is created inside the solution, all subsequent links to environment variables and connection references remain intact across environments.

Defining Environment Variables & Connection References

Rather than embed connection details in individual screens, store them centrally:

 

  1. Environment Variables – In your solution, click New > Environment variable three times to create:
    • DataverseURL (Text): URL of your Dataverse instance
    • SharePointSite (URL): URL of the SharePoint site for legacy lists
    • PaymentGatewayKey (Secret): API key for your payment connector
  2. Connection References – Click New > Connection reference and select:
    • Dataverse – bind to DataverseURL
    • SharePoint – bind to SharePointSite
    • HTTP with Entra ID – bind to PaymentGatewayKey

Rename them for clarity (e.g. CR_Dataverse, CR_SP, CR_Payment).

These references allow your Canvas App to add data sources without hard-coding credentials, streamlining both development and deployments.

Best Practices for Solution-Aware Canvas Apps
  • Consistent Naming – Prefix solution components (app_SolestylesCanvas, env_DataverseURL).
  • Avoid Ad-Hoc Connections – Always use your predefined connection references in Power Apps Studio.
  • Document in the Solution – Use the solution’s Description fields to explain each environment variable and reference.
  • Version Control – Increment the solution version with each release and store exported solution files in your source control system.

 

By investing time upfront to structure your solution and by embedding key settings in environment variables and connection references, you set the stage for a stable, secure and scalable Canvas App that can grow with Solestyles Boutique.

Connecting to Dataverse & SharePoint

The cornerstone of the Canvas App is its seamless access to Solestyles core data:

 

  • product catalogues,
  • order histories, and
  • customer records; housed in Dataverse,

 

alongside legacy inventory logs stored in SharePoint. Rather than hard-code connection details into each screen, I embraced solution-aware connections and environment variables to ensure consistency across development, test and production environments.

 

At the heart of this approach lies the Data pane in Power Apps Studio. Within the Solestyles solution, I first created two environment variables:

 

  • DataverseURL pointing to the boutique’s Dataverse instance
  • SharePointSite referencing the SharePoint Online site hosting the legacy lists

 

These variables live in the Solution but outside of the Canvas App, allowing us to migrate the entire solution package without manual reconnects. In the Canvas App’s Data pane, I then added two Connection references, each bound to its respective environment variable. Once configured, the app draws on these references for every data operation, greatly reducing drift between environments and ensuring consistent security settings.

Organising Collections vs Direct Lookups

While direct LookUp and Filter calls to Dataverse and SharePoint are perfectly serviceable, they can incur latency; especially when scanning large product tables over mobile broadband. To mitigate this, Solestyles Canvas App uses a two-tiered strategy:

Global Collections at Startup

On app launch, essential, static tables such as product categories and supplier lists via a single ClearCollect call is obtained:

 

ClearCollect(

colCategories,
DataverseTable.Run(DataverseURL & "/api/data/v9.1/productcategories")

);

 

By storing these small datasets in the local colCategories collection, screens deeper in the app can reference them instantly, without round-trips to the server.

Delegable Direct Queries

For large tables like Products or Orders, the app relies on delegable functions (Filter, Sort, Search) that off-load the work to Dataverse. This way, the server returns only matching records rather than the entire table:

 

Filter(

Products,

StartsWith(Name, txtSearch.Text)

);

 

Where legacy SharePoint lists remain useful for example, tracking ad-hoc inventory adjustments; I added a SharePoint connector using the same environment-variable pattern. However, I limit queries to sub-500-row batches (using Top and Skip) or load them into temporary collections for offline edits, avoiding delegation errors and throttling.

Best Practices for Security and Performance

Securing data at the source is non-negotiable for any retail operation. By using connection references with OAuth authentication, Dataverse honour’s the user’s identity and privileges:

If a shop assistant lacks permission to view wholesale order tables, the Canvas App won’t surface them.

I further scoped Dataverse table permissions in the Model-Driven environment, ensuring the Canvas connector cannot over-reach.

To sharpen performance:

 

  • Index key columns (Name, Category) in Dataverse for rapid server-side filtering.
  • Avoid nested ForAll loops by leveraging formula chaining and single ClearCollect calls.
  • Monitor network calls with the App’s performance profiler, iterating until load times for critical galleries fell below two seconds.

 

This careful orchestration of environment variables, connection references and local caching means the Solestyles Canvas App reliably pulls its data from Dataverse and SharePoint no matter whether the user is on the shop floor’s Wi-Fi or an unpredictable mobile network.

Screen Architecture & Navigation

When someone picks up the Solestyles Canvas App, they should never wonder where to tap next. I designed a streamlined five-icon header; Home, Search, Cart, Account and Plus (for staff-only actions) to keep every key function within a thumb’s reach. This custom navigation bar replaces the clutter of slide-out menus and ensures that users can move effortlessly from browsing to buying in just a few taps.

Home/Gallery Screen
Grid Layout

Displays product thumbnails in a responsive grid that displays high-resolution product thumbnails or inspection records.

Search Box

sits prominently at the top, filter­ing live as you type to avoid the delegation pitfalls of returning entire tables to the client.

Plus Icon

The “Plus” icon in the header launches a staff-only form for creating special orders or recording pop-up stock counts, keeping employee actions separate from customer-facing processes.

Detail Screen with Add to Cart
Triggered by tapping a gallery item
  • Product Image: Shows high-resolution product image, description and price.
  • Size and Colour Selectors: Dropdown and swatch controls bound to choice columns in Dataverse.
  • Quantity Spinner: – and + buttons to adjust quantity, with a minimum of 1.
  • Add to Cart: Button that runs a local collection update:

 

Collect(

colCart,

Patch(

Defaults(Cart),

{

ProductID: ThisItem.ProductID,

Size: drpSize.Selected.Value,

Colour: drpColour.Selected.Value,

Quantity: varQuantity

}

)

);

 

  • Back Icon: Returns the user to the Home screen without losing cart state.
Cart Screen
  • Accessed via the Cart icon in the header.
  • Lists items in colCart with thumbnails, details and totals.
  • Edit: Inline quantity updates with Patch and Remove “Bin” icon to delete items.
  • Checkout Button: Navigates to the order summary form.
Checkout, Order and Pay 
Checkout process (summary):
  • Delivery vs Collection: Radio buttons choose shipping method.
  • Conditional Fields:
    • If Delivery, show address form fields.
    • If Collect, show a dropdown of store locations (Dataverse Store table).
  • Payment Section: Secure credit/debit-card entry control (PCI-compliant connector).
  • Pay Now: Button that triggers a Power Automate flow:

 

PowerAutomate.Run (

JSON (

{

CartItems: colCart,

UserID: varUserID,

ShippingMethod: drpShipping.Selected.Value,

Address: txtAddress.Text,

PaymentToken: ccControl.Token

}

)

);

 

The payment process (summary):
  1. Validates Payment: Calls payment gateway API.
  2. Stores Order: Creates records in Dataverse Orders and OrderLines tables.
  3. Adjusts Inventory: Updates Products stock levels.
  4. Sends Notifications: Email/SMS confirmations via Office 365.
  5. Clears Cart: Responds back to the App to Clear(colCart).
Success Popup:
  • Message: “Hi @{User().FullName}, thank you for your order! Payment received and your Order ID @{OrderID} is being processed.”
    • Complete (Button): Closes popup, clears cart and returns to Home.
Error Handling:

If payment fails, show a retry/cancel popup.

  • Message: “Payment could not be processed. Would you like to retry?”
    • Retry (Button): Returns to Checkout with cart intact.
    • Cancel (Button): Runs Clear(colCart) and Navigate(HomeScreen).
Account/Login
  • User Icon: Opens a login form or profile view if already authenticated.
    • Offers a Register option: A simple sign-up form captures name, email and password, then provisions a Dataverse Customer record.
  • Once authenticated, the panel transforms into a Profile view, displaying:
    • Order History: A list of in-progress and past orders, fetched in real time from Dataverse.
    • Update Details: Quick links to edit contact or delivery preferences.
  • Logout: Clears varUserID and redirects to Home.

 

By weaving these screens together with consistent, icon-driven navigation and carefully choreographed transitions, I ensured that Solestyles Canvas App feels as intuitive as any consumer-grade shopping experience yet is backed by the full power, security and flexibility of the Microsoft Power Platform.

Search, Filter & Delegation

In a Canvas App that must handle thousands of product records, naïve local filtering will quickly bump into the default 500-record limit and degrade performance. At Solestyles, I embraced Power Apps’ delegation model to offload data processing to Dataverse, ensuring that search and filter operations return only the relevant subset of records, regardless of the table size.

Delegable Functions

Power Apps will delegate certain data operations to the server when the underlying data source supports it. Dataverse delegates functions like Filter, Sort, Search (when paired with StartsWith), and many comparison operators. Non-delegable calls, by contrast, run client-side against the first 500 records only, risking incomplete or inaccurate results.

Building a Multi-Field, Delegable Search

The primary search box lets shop assistants type keywords; style names, SKU codes or designer collections; and immediately see matching products. I bound the search input to a variable:

 

// OnChange of txtSearch:
Set(varSearch, Lower(txtSearch.Text))

 

Then, in the gallery’s Items property:

 

Filter(
  Products,
  Or(
    StartsWith(Lower(Name), varSearch),
    StartsWith(Lower(SKU), varSearch),
    StartsWith(Lower(Category), varSearch)
  )
)

 

By using StartsWith, you remain fully delegable; by normalising both sides with Lower, you avoid case-sensitivity issues.

Layering in Additional Filters

Beyond free-text search, users can narrow results by category or stock availability. I added a dropdown drpCategory and a toggle tglInStock, then wrapped them together:

 

Filter(
  Products,
  (
    varSearch = "" ||
    Or(
      StartsWith(Lower(Name), varSearch),
      StartsWith(Lower(SKU), varSearch)
    )
  ) &&
  (drpCategory.Selected.Value = "All" || Category = drpCategory.Selected.Value) &&
  (!tglInStock.Value || InStock = true)
)

 

This single, server-side query handles all combinations, always returning the correct data.

Delegable Sorting

Users often want to sort by price or release date. Since Sort is delegable, I chained it after the filters:

 

Sort(
  FilteredProducts,
  If(drpSort.Selected.Value = "Price", Price, ReleaseDate),
  If(btnSortDesc.Pressed, Descending, Ascending)
)

 

Monitoring and Troubleshooting Delegation

I leveraged App Checker and Performance Profiling tools to flag any non-delegable calls. For small, static lookup tables such as Categories, I preloaded them into collections on OnStart, eliminating delegation concerns for those controls altogether:

 

ClearCollect(colCategories, Categories);

 

Best Practices
  • Use delegable functions for all large-table operations.
  • Use StartsWith to remain within delegation constraints.
  • Normalise case with Lower to avoid mismatches.
  • Combine filters into one query where possible to minimise server round-trips.
  • Fetch static lookups into collections at startup for instant local references.

 

By architecting search, filter and sort to run on the server, Solestyles Canvas App scales elegantly – from 500 products to 50,000 – while preserving sub-two-second response times and a seamless user experience.

Forms, Galleries & Data Edits

A truly robust Canvas App combines clean visual galleries with intuitive forms for data entry and editing. For Solestyles, I crafted a tightly integrated experience where users can select, view and modify records without ever straying from the familiar gallery form viewpoint.

Customising Display & Edit Forms

Canvas Apps offer Form controls; DisplayForm and EditForm; that bind directly to Dataverse tables. For every record type (Products, Orders, CartItems), I created a dedicated form:

 

// On Success of frmCartItem:
SubmitForm(frmCartItem);
// Refresh the gallery to reflect changes
Refresh(CartItems);

 

I placed each form on its own screen, with the Item property set to the selected record from the gallery:

 

frmCartItem.Item = galCart.Selected

 

Data Cards & Validation

Inside each Form control, DataCards represent individual fields. I configured them to enforce business rules:

 

  • Required Fields: Set Required = true on Colour and Size choice cards.
  • Numeric Ranges: On the Quantity card, I set Min = 1 and Max = ThisItem.InStock to prevent over-ordering.
  • Custom Validation: For delivery addresses, I used a Regex match in the card’s Valid property to ensure UK postcode format.

 

Error messages appear inline by setting the DataCard’s ErrorMessage property, guiding users to correct input without cryptic pop-ups.

Thumbnail Galleries for Quick Scanning

Long lists of products or orders benefit from compact thumbnail galleries. I optimised the Solestyles Boutique gallery by:

 

  • Reduced TemplateSize: 80 pixels height, with TemplatePadding = 8.
  • AspectRatioMode = Fit: Ensuring images never distort.
  • FillPortion: Setting the image control’s ImagePosition so that key product features remain in view.

 

Selecting a gallery item triggers the OnSelect:

 

UpdateContext({varSelected: ThisItem});
Navigate(scrCartItemForm, ScreenTransition.Fade)

 

Inline Data Editing Patterns

For some use cases; like adjusting quantities in the cart; I embedded small input controls directly within gallery templates. A numeric spinner control inside each gallery item allows quick adjustments:

 

// OnChange of quantity spinner:
Patch(
  CartItems,
  ThisItem,
  { Quantity: Self.Value }
);

 

Because Patch is delegable for single-record updates, these inline edits bypass the need for a full form and eliminate nonessential navigation.

Synchronising Changes

When users work offline, all edits go into local collections (SaveData/LoadData). On reconnect, these local collections are reconciled:

 

If(Connection.Connected,
   ForAll(colCartChanges, Patch(CartItems, LookUp(CartItems, ID = CartID), { Quantity: NewQty })),
   Notify("You must be online to save changes", NotificationType.Error)
);

 

This approach ensures that whether on the shop floor or at a remote pop-up, data remains accurate and user edits aren’t lost.

Offline-First Strategies

In retail, connectivity can vanish in an instant; whether you’re in the boutique’s back office when the Wi-Fi cuts out, or at a weekend pop-up stall where mobile signal is spotty at best.

 

Offline-First isn’t an optional feature; it’s a cornerstone of reliability and user confidence. Imagine a customer waiting patiently for a new delivery time during a sudden network outage, or a manager updating special orders in a car park without internet. The Solestyles Canvas App needed to ensure that no sale stalls and no stock check slips through the cracks, regardless of connectivity.

Embracing Local Caching

From the moment the app launches, the latest data is loaded into local collections. On App.OnStart, the logic looks like this:

 

If(
    Connection.Connected,
    ClearCollect(colProducts, Products),
    LoadData(colProducts, "ProductsCache", false)
);

 

  • ClearCollect fetches fresh records from Dataverse when online.
  • LoadData reloads the last-known snapshot when offline.
  • I mirrored this pattern across critical tables: Orders, CartItems, and Categories, storing each in a persistent cache.
Queued Change Tracking

Rather than attempt immediate writes to Dataverse (which would fail offline), I queued edits in a colPendingChanges collection. Each user action – changing a cart quantity, updating an address records:

 

Collect(
    colPendingChanges,
    {
        Table: "CartItems",
        RecordID: galCart.Selected.ID,
        Updates: { Quantity: varNewQty }
    }
);

 

This approach guarantees that every change is captured locally, even if the network drops mid-edit.

Syncing on Reconnect

When the device regains connectivity, an OnVisible or Sync Now button initiates reconciliation:

 

If(
    Connection.Connected,
    ForAll(
        colPendingChanges,
        Patch(
            Table(Updates.Table),
            LookUp(Table(Updates.Table), ID = Updates.RecordID),
            Updates.Updates
        )
    );
    Clear(colPendingChanges);
    SaveData(colProducts, "ProductsCache")
)

 

  • ForAll(Patch()) reapplies each pending update server-side.
  • Clear wipes the local queue to prevent duplicates.
  • SaveData refreshes the local cache for next offline session.
Conflict Resolution Patterns

Occasionally, two users might edit the same record offline. To prevent blind overwrites, I compare ModifiedOn timestamps:

 

With(
    { serverRec: LookUp(CartItems, ID = recID) },
    If(
        serverRec.ModifiedOn > recClient.ModifiedOn,
        Notify("Someone else updated this record; please review.", NotificationType.Warning),
        Patch(...)
    )
)

 

I present a lightweight dialog offering to Keep My Change, Use Server Value, or Merge Manually, ensuring data integrity and user control.

User Feedback & Control

A persistent banner informs users of their connection state:

Offline Mode – Your changes will sync automatically when you’re back online.

For more urgent needs, a Sync Now button allows immediate retries, with clear notifications for success or any errors. By treating offline as a first-class scenario; caching data, queuing edits and guiding users through syncs; I deliver a seamless experience that keeps Solestyles running smoothly, no matter where the day takes them.

Integrating Power Automate Flows

Canvas Apps shine at the user interface, but it’s Power Automate flows that handle the heavy lifting; processing payments, updating inventory, sending notifications and more. In this section, you’ll see how the Solestyles’ Canvas App invokes these flows and manages their responses, while reserving a deeper exploration for Post 4.

Invoking Flows from Canvas

Every critical action in the app triggers a corresponding flow. For example, when a customer taps Pay Now, I package the cart and user details into a JSON payload and call the OrderProcessingFlow:

 

// OnSelect of Pay Now button
Set(
  varResponse,
  OrderProcessingFlow.Run(
    JSON(
      {
        CartItems: colCart,
        UserID: varUserID,
        DeliveryMethod: drpDelivery.Selected.Value,
        Address: If(drpDelivery.Selected.Value = "Delivery", txtAddress.Text, "")
      }
    )
  )
);

// Provide immediate user feedback
If(
  varResponse.Status = "Success",
  Notify("Payment successful! Your order is processing.", NotificationType.Success),
  Notify("Payment failed. Please try again.", NotificationType.Error)
);

 

By capturing the flow’s response in varResponse, the app can display a succinct success or error notification, complete with retry logic if needed.

Key Flows Overview
  • OrderProcessingFlow
    1. Validates payment through our PCI-compliant gateway.
    2. Creates Orders and OrderLines records in Dataverse.
    3. Patches Products to decrement stock levels.
    4. Sends confirmation emails/SMS via the Office 365 connector.
  • SpecialOrderFlow
    Triggered by staff via the Plus → New Special Order button. Creates a SpecialOrders record, then notifies the buying team by email and posts an alert in Microsoft Teams.
  • InventoryAlertFlow
    A scheduled hourly flow that queries Dataverse for products where StockLevel falls below ReorderThreshold. Collates results and emails the procurement lead with low-stock details.

 

Each flow is packaged in the solution, uses environment variables for connection references, and groups actions into Scope blocks with Configure run-after rules for retries and fallbacks (e.g. run after Failure to send an admin alert).

UI Feedback & Design Patterns
  • Spinners and Flags
    While a flow runs, I display a LoadingSpinner control and set a Boolean varIsProcessing to disable buttons.
  • Error Handling in Canvas
    If a flow fails (for example, payment gateway down), we read varResponse.StatusCode and present a retry option:

 

If(
  varResponse.StatusCode <> 200,
  Notify(
    "There was a problem processing your order. Tap Retry to try again.",
    NotificationType.Error,
    { ButtonText: "Retry", OnSelect: RestartFlow }
  )
);

 

  • Solution-Aware Deployment
    All flows live in the same solution as the Canvas App, meaning migrations between environments preserve connections, variables and permissions.

 

By tightly coupling Canvas triggers with resilient, solution-aware flows, Solestyles achieves a seamless, end-to-end process; from the moment a customer taps Pay Now to the final email confirmation, every step is automated and transparent. In Post 4, I’ll dissect these flows in detail; building, testing and troubleshooting each component.

UI/UX Polish & Performance Tuning

This image shows Solestyles Canvas App on a tablet in the foreground with a loading spinner indicating an active operation and a blurred monitor in the background displaying a performance profiler graph. It symbolises the commitment to both UI polish and measurable performance.

 

A powerful app only earns user loyalty when it feels polished, responsive and on-brand. For Solestyles, I invested equally in aesthetics and under-the-hood optimisations to deliver a Canvas App that delights at every tap. This is important to understand; UI/UX polish is far more complex, but appealing for the majority of Microsoft 365 applications, after all yes you can still have a “boring” Out-of-the-Box boring UI and UX, but is it going to entice your end users to want to use it? Like everything, UX and UI polish, refinement and development takes additonal time, head-scratching, but happiness in making your clients go “WOW”.

Theming with Fluent UI

Rather than hard-code colours and fonts, I adopted the Fluent Design System’s theme variables:

  • Defined a custom theme JSON in the solution:

 

{
  "primaryColor": "#2C2A29",
  "secondaryColor": "#D4A373",
  "textColor": "#333333",
  "accentColor": "#F4E1D2"
}

 

  • Bound controls’ Fill, Color and BorderColor to theme variables (Theme.primaryColor, Theme.accentColor), ensuring brand consistency and easy updates across the app.
Adaptive, Responsive Layouts

With tablets in landscape and portrait, screens auto-adapt using relative formulas:

 

// For a gallery control:
Gallery1.Width = Parent.Width * 0.9;
Gallery1.TemplateSize = If(Parent.Width > Parent.Height, 120, 80);

 

  • Used Visible properties to hide non-critical elements on narrower views:

 

(HeaderNav.Visible = Parent.Width > 600)

 

Startup Performance & Concurrent Loads

Long OnStart sequences can stall user access. I parallelised data loads:

 

Concurrent(
  ClearCollect(colProducts, Products),
  ClearCollect(colCategories, Categories),
  ClearCollect(colCart, CartItems)
);

 

  • This reduced cold-start time by 40%.
  • Removed unnecessary hidden screens and controls to minimise the app’s DOM complexity.
Smooth Transitions & Loading Indicators

No one likes staring at a frozen screen so I layered in:

  • ScreenTransition.Fade for navigation:
    • Navigate(scrDetail, Fade).
  • A global varIsLoading flag toggled by data calls:

 

Set(varIsLoading, true);
// data call...
Set(varIsLoading, false);

 

  • A LoadingSpinner overlay with Visible = varIsLoading, masking mid-air glitches.
Accessibility & Keyboard Support

Canvas Apps can be accessible too:

 

  • Set the AccessibleLabel on every icon, gallery item and form field.
  • Define a TabIndex to ensure logical keyboard navigation.
  • Test in high-contrast mode and with screen readers, meeting WCAG 2.1 AA standards.
Telemetry & Monitoring

I integrated Azure Application Insights to offer Monitoring and Telemetry result analysis:

 

// OnVisible of each screen:
Telemetry.TrackPageView("GalleryScreen");

 

  • Captured startup time, control render durations and error events.
  • Monitored metrics to catch regressions before they reached users.

Conclusion & Next Steps

As I draw the curtain on my deep dive (apologies for the length, but it is necessary) into Solestyles Boutique’s Canvas App, it’s worth pausing to reflect on how far the solution has come. What began as a simple idea to replace paper invoices and scattered spreadsheets with a mobile-first interface has blossomed into a resilient, feature-rich application. From offline caching and multi-field delegable search to seamless integration with Power Automate, every layer of the app showcases best practices in low-code design.

Key takeaways:
  • User-Centred Navigation: A custom five-icon header ensures that Home, Search, Cart, Account and Staff functions are always just one tap away.
  • Data Accuracy & Performance: Delegation, caching and concurrency optimisations keep large datasets accessible and fast, even on 4G mobile service connections.
  • Seamless Automation: Power Automate flows, invoked directly from the Canvas App, handle payments, notifications and stock updates without a manual dependency.
  • Reliability in Any Network: Offline-first patterns guarantee that every edit is captured and synchronised, maintaining continuity in the shop, at market stalls or on the move.
  • Polished, On-Brand Experience: A consistent use of Fluent UI theming, adaptive layouts and accessibility features makes the app both beautiful and inclusive.
What’s Coming Up in the Solestyles Series

With the Canvas App serving as the frontline interface, the next logical step is to explore how Solestyles managers and back-office staff interact with the same data through a Model-Driven App. In Part 3, I’ll:

  • Design Dataverse Tables and Relationships: Model products, orders, customers and special requests with lookups, choices and roll-up fields.
  • Craft Business Process Flows and Rules: Guide users through approval steps, enforce data quality and automate record transitions.
  • Build Rich Forms, Views and Dashboards: Surface actionable insights and embed Power BI charts directly within the Model-Driven experience.
  • Configure Role-Based Security: Define table permissions, roles and field-level security so each user sees exactly what they need.

 

Stay tuned for Part 3: Unlocking Model-Driven Apps for Solestyles Boutique, where I’ll continue the journey into a truly end-to-end Power Platform solution.

 

Thank you for following along. If you have questions about any Canvas patterns I have covered; whether delegation nuances, offline caching intricacies or flow-invocation syntax; drop a comment or fill in the contact me form. I look forward to diving into the next part with you.

Leave a Reply

Mark Tonks
aka. SharePointMark

Microsoft Solution Architect, Senior Project Manager, and Mental Health Advocate

Mark Tonks
Business Links